Jofthomas HF staff commited on
Commit
ce8b18b
β€’
1 Parent(s): 562f7ad
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. .DS_Store +0 -0
  2. .dockerignore +39 -0
  3. .eslintignore +7 -0
  4. .eslintrc.js +22 -0
  5. .gitattributes +0 -35
  6. .github/workflows/hf-sync.yml +0 -22
  7. .gitignore +45 -0
  8. .prettierrc +7 -0
  9. .vscode/convex.code-snippets +102 -0
  10. .vscode/settings.json +21 -0
  11. ARCHITECTURE.md +301 -0
  12. Dockerfile +0 -17
  13. Justfile +30 -0
  14. LICENSE +21 -0
  15. README.md +434 -25
  16. README.md.yml +0 -18
  17. {patches/assets β†’ assets}/32x32folk.png +0 -0
  18. {patches/assets β†’ assets}/GrayCat.png +0 -0
  19. {patches/assets β†’ assets}/OrangeCat.png +0 -0
  20. {patches/assets β†’ assets}/a16z.png +0 -0
  21. {patches/assets β†’ assets}/background.webp +0 -0
  22. {patches/assets β†’ assets}/close.svg +0 -0
  23. {patches/assets β†’ assets}/cloud.jpg +0 -0
  24. {patches/assets β†’ assets}/convex-bg.webp +0 -0
  25. {patches/assets β†’ assets}/convex.svg +0 -0
  26. {patches/assets β†’ assets}/favicon.ico +0 -0
  27. {patches/assets β†’ assets}/fonts/upheaval_pro.ttf +0 -0
  28. {patches/assets β†’ assets}/fonts/vcr_osd_mono.ttf +0 -0
  29. {patches/assets β†’ assets}/heart-empty.png +0 -0
  30. {patches/assets β†’ assets}/help.svg +0 -0
  31. {patches/assets β†’ assets}/hf.svg +0 -0
  32. {patches/assets β†’ assets}/interact.svg +0 -0
  33. {patches/assets β†’ assets}/magecity.png +0 -0
  34. map.png β†’ assets/map.png +0 -0
  35. {patches/assets β†’ assets}/map_night.png +0 -0
  36. {patches/assets β†’ assets}/player.png +0 -0
  37. {patches/assets β†’ assets}/rpg-tileset.png +0 -0
  38. {patches/assets β†’ assets}/spritesheets/campfire.png +0 -0
  39. {patches/assets β†’ assets}/spritesheets/gentlesparkle32.png +0 -0
  40. {patches/assets β†’ assets}/spritesheets/gentlewaterfall32.png +0 -0
  41. {patches/assets β†’ assets}/spritesheets/windmill.png +0 -0
  42. {patches/assets β†’ assets}/star.svg +0 -0
  43. {patches/assets β†’ assets}/tilemap.json +0 -0
  44. {patches/assets β†’ assets}/ui/box.svg +0 -0
  45. {patches/assets β†’ assets}/ui/bubble-left.svg +0 -0
  46. {patches/assets β†’ assets}/ui/bubble-right.svg +0 -0
  47. {patches/assets β†’ assets}/ui/button.svg +0 -0
  48. {patches/assets β†’ assets}/ui/button_pressed.svg +0 -0
  49. {patches/assets β†’ assets}/ui/chats.svg +0 -0
  50. {patches/assets β†’ assets}/ui/desc.svg +0 -0
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
.dockerignore ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ game/node_modules/
6
+ /.pnp
7
+ .pnp.js
8
+
9
+ # testing
10
+ /coverage
11
+
12
+ # next.js
13
+ /.next/
14
+ /out/
15
+
16
+ # production
17
+ /build
18
+
19
+ # misc
20
+ .DS_Store
21
+ *.pem
22
+
23
+ # debug
24
+ npm-debug.log*
25
+ yarn-debug.log*
26
+ yarn-error.log*
27
+
28
+ # local env files
29
+ .env*.local
30
+
31
+ # vercel
32
+ .vercel
33
+
34
+ # typescript
35
+ *.tsbuildinfo
36
+ next-env.d.ts
37
+ .env
38
+ /.env.prod
39
+ /fly.toml
.eslintignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ webpack*
2
+ .eslintrc.js
3
+ next.config.js
4
+ tailwind.config.js
5
+ postcss.config.js
6
+ convex/_generated/*
7
+ dist/*
.eslintrc.js ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export default {
2
+ parser: '@typescript-eslint/parser', // Specifies the ESLint parser
3
+ plugins: ['@typescript-eslint'],
4
+ extends: [
5
+ 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
6
+ 'plugin:@typescript-eslint/recommended-type-checked',
7
+ ],
8
+ parserOptions: {
9
+ project: './tsconfig.json',
10
+ ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
11
+ sourceType: 'module', // Allows for the use of imports
12
+ },
13
+ rules: {
14
+ '@typescript-eslint/no-explicit-any': 'off',
15
+ '@typescript-eslint/explicit-function-return-type': 'off',
16
+ '@typescript-eslint/no-unused-vars': [
17
+ 'warn',
18
+ { varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
19
+ ],
20
+ '@typescript-eslint/no-non-null-assertion': 'off',
21
+ },
22
+ };
.gitattributes DELETED
@@ -1,35 +0,0 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.github/workflows/hf-sync.yml DELETED
@@ -1,22 +0,0 @@
1
- name: Sync to Hugging Face Spaces
2
- on:
3
- push:
4
- branches:
5
- - main
6
- jobs:
7
- sync:
8
- name: Sync
9
- runs-on: ubuntu-latest
10
- steps:
11
- - name: Checkout Repository
12
- uses: actions/checkout@v4
13
- with:
14
- lfs: true
15
- - name: Sync to Hugging Face Spaces
16
- uses: JacobLinCool/huggingface-sync@v1
17
- with:
18
- github: ${{ secrets.GITHUB_TOKEN }}
19
- user: ${{ vars.HF_SPACE_OWNER }}
20
- space: ${{ vars.HF_SPACE_NAME }}
21
- token: ${{ secrets.HF_TOKEN }}
22
- configuration: "README.md.yml"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ game/node_modules/
6
+ /.pnp
7
+ .pnp.js
8
+
9
+ # testing
10
+ /coverage
11
+
12
+ # next.js
13
+ /.next/
14
+ /out/
15
+
16
+ # production
17
+ /build
18
+
19
+ # misc
20
+ .DS_Store
21
+ *.pem
22
+
23
+ # debug
24
+ npm-debug.log*
25
+ yarn-debug.log*
26
+ yarn-error.log*
27
+
28
+ # local env files
29
+ .env*.local
30
+
31
+ # vercel
32
+ .vercel
33
+
34
+ # typescript
35
+ *.tsbuildinfo
36
+ next-env.d.ts
37
+ .env
38
+ /.env.prod
39
+ /fly.toml
40
+
41
+ # Vite build
42
+ dist
43
+ convex-local-backend*
44
+ convex_local_storage
45
+ convex_local_backend.sqlite3
.prettierrc ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "trailingComma": "all",
3
+ "singleQuote": true,
4
+ "bracketSpacing": true,
5
+ "tabWidth": 2,
6
+ "printWidth": 100
7
+ }
.vscode/convex.code-snippets ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "Convex Imports": {
3
+ "prefix": "convex:imports",
4
+ "body": [
5
+ "import { v } from \"convex/values\";",
6
+ "import { api, internal } from \"./_generated/api\";",
7
+ "import { Doc, Id } from \"./_generated/dataModel\";",
8
+ "import {",
9
+ " action,",
10
+ " internalAction,",
11
+ " internalMutation,",
12
+ " internalQuery,",
13
+ " mutation,",
14
+ " query,",
15
+ "} from \"./_generated/server\";"
16
+ ],
17
+ "scope": "javascript,typescript",
18
+ "isFileTemplate": true
19
+ },
20
+
21
+ "Convex Query": {
22
+ "prefix": "convex:query",
23
+ "body": [
24
+ "export const $1 = query({",
25
+ " args: {},",
26
+ " handler: async (ctx, args) => {",
27
+ " $0",
28
+ " },",
29
+ "});"
30
+ ],
31
+ "scope": "javascript,typescript"
32
+ },
33
+
34
+ "Convex Internal Query": {
35
+ "prefix": "convex:internalQuery",
36
+ "body": [
37
+ "export const $1 = internalQuery({",
38
+ " args: {},",
39
+ " handler: async (ctx, args) => {",
40
+ " $0",
41
+ " },",
42
+ "});"
43
+ ],
44
+ "scope": "javascript,typescript"
45
+ },
46
+
47
+ "Convex Mutation": {
48
+ "prefix": "convex:mutation",
49
+ "body": [
50
+ "export const $1 = mutation({",
51
+ " args: {},",
52
+ " handler: async (ctx, args) => {",
53
+ " $0",
54
+ " },",
55
+ "});"
56
+ ],
57
+ "scope": "javascript,typescript"
58
+ },
59
+
60
+ "Convex Internal Mutation": {
61
+ "prefix": "convex:internalMutation",
62
+ "body": [
63
+ "export const $1 = internalMutation({",
64
+ " args: {},",
65
+ " handler: async (ctx, args) => {",
66
+ " $0",
67
+ " },",
68
+ "});"
69
+ ],
70
+ "scope": "javascript,typescript"
71
+ },
72
+
73
+ "Convex Action": {
74
+ "prefix": "convex:action",
75
+ "body": [
76
+ "import { action } from \"./_generated/server\";",
77
+ "",
78
+ "export const $1 = action({",
79
+ " args: {},",
80
+ " handler: async (ctx, args) => {",
81
+ " $0",
82
+ " },",
83
+ "});"
84
+ ],
85
+ "scope": "javascript,typescript"
86
+ },
87
+
88
+ "Convex Internal Action": {
89
+ "prefix": "convex:internalAction",
90
+ "body": [
91
+ "import { internalAction } from \"./_generated/server\";",
92
+ "",
93
+ "export const $1 = internalAction({",
94
+ " args: {},",
95
+ " handler: async (ctx, args) => {",
96
+ " $0",
97
+ " },",
98
+ "});"
99
+ ],
100
+ "scope": "javascript,typescript"
101
+ }
102
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "editor.formatOnSave": true,
3
+ "editor.tabSize": 2,
4
+ "[html]": {
5
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
6
+ },
7
+ "[javascript]": {
8
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
9
+ },
10
+ "[jsonc]": {
11
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
12
+ },
13
+ "[typescript]": {
14
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
15
+ },
16
+ "[typescriptreact]": {
17
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
18
+ },
19
+ "typescript.preferences.importModuleSpecifierEnding": "auto",
20
+ "javascript.preferences.importModuleSpecifierEnding": "auto"
21
+ }
ARCHITECTURE.md ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Architecture
2
+
3
+ This documents dives into the high-level architecture of AI Town and its different layers. We'll
4
+ first start with a brief overview and then go in-depth on each component. The overview should
5
+ be sufficient for forking AI Town and changing game or agent behavior. Read on to the deep dives
6
+ if you're interested or running up against the engine's limitations.
7
+
8
+ This doc assumes the reader has a working knowledge of Convex. If you're new to Convex, check out
9
+ the [Convex tutorial](https://docs.convex.dev/get-started) to get started.
10
+
11
+ ## Overview
12
+
13
+ AI Town is split into a few layers:
14
+
15
+ - The server-side game logic in `convex/aiTown`: This layer defines what state AI Town maintains,
16
+ how it evolves over time, and how it reacts to user input. Both humans and agents submit inputs
17
+ that the game engine processes.
18
+ - The client-side game UI in `src/`: AI Town uses `pixi-react` to render the game state to the
19
+ browser for human consumption.
20
+ - The game engine in `convex/engine`: To make it easy to hack on the game rules, we've separated
21
+ out the game engine from the AI Town-specific game rules. The game engine is responsible for
22
+ saving and loading game state from the database, coordinating feeding inputs into the engine,
23
+ and actually running the game engine in Convex functions.
24
+ - The agent in `convex/agent`: Agents run as part of the game loop, and can kick off asynchronous
25
+ Convex functions to do longer processing, such as talking to LLMs. Those functions can save state
26
+ in separate tables, or submit inputs to the game engine to modify game state. Internally, our
27
+ agents use a combination of simple rule-based systems and talking to an LLM.
28
+
29
+ So, if you'd like to tweak agent behavior but keep the same game mechanics, check out `convex/agent`
30
+ for the async work, and `convex/aiTown/agent.ts` for the game loop logic.
31
+ If you would like to add new gameplay elements (that both humans and agents can interact with), add
32
+ the feature to `convex/aiTown`, render it in the UI in `src/`, and respond to it in `convex/aiTown/agent.ts`.
33
+
34
+ If you have parts of your game that are more latency sensitive, you can move them out of engine
35
+ into regular Convex tables, queries, and mutations, only logging key bits into game state. See
36
+ "Message data model" below for an example.
37
+
38
+ ## AI Town game logic (`convex/aiTown`)
39
+
40
+ ### Data model
41
+
42
+ AI Town's data model has a few concepts:
43
+
44
+ - Worlds (`convex/aiTown/world.ts`) represent a map with many players interacting together.
45
+ - Players (`convex/aiTown/player.ts`) are the core characters in the game. Players have human readable names and
46
+ descriptions, and they may be associated with a human user. At any point in time, a player may be pathfinding
47
+ towards some destination and has a current location.
48
+ - Conversations (`convex/aiTown/conversations.ts`) are created by a player and end at some point in time.
49
+ - Conversation memberships (`convex/aiTown/conversationMembership.ts`) indicate that a player is a member
50
+ of a conversation. Players may only be in one conversation at any point in time, and conversations
51
+ currently have exactly two members. Memberships may be in one of three states:
52
+ - `invited`: The player has been invited to the conversation but hasn't accepted yet.
53
+ - `walkingOver`: The player has accepted the invite to the conversation but is too far away to talk. The
54
+ player will automatically join the conversation when they get close enough.
55
+ - `participating`: The player is actively participating in the conversation.
56
+
57
+ ### Schema
58
+
59
+ There are three main categories of tables:
60
+
61
+ 1. Engine tables (`convex/engine/schema.ts`) for maintaining engine-internal state.
62
+ 2. Game tables (`convex/aiTown/schema.ts`) for game state. To keep game state small and efficient to
63
+ read and write, we store AI Town's data model across a few tables. See `convex/aiTown/schema.ts` for an overview.
64
+ 3. Agent tables (`convex/agent/schema.ts`) for agent state. Agents can freely read and write to these tables
65
+ within their actions.
66
+
67
+ ### Inputs (`convex/aiTown/inputs.ts`)
68
+
69
+ AI Town modifies its data model by processing inputs. Inputs are submitted by players and agents and
70
+ processed by the game engine. We specify inputs in the `inputs` object in `convex/aiTown/inputs.ts`.
71
+ Use the `inputHandler` function to construct an input handler, specifying a Convex validator for
72
+ arguments for end-to-end type-safety.
73
+
74
+ - Joining (`join`) and leaving (`leave`) the game.
75
+ - Moving a player to a particular location (`moveTo`): Movement in AI Town is similar to RTS games, where
76
+ the players specify where they want to go, and the engine figures out how to get there.
77
+ - Starting a conversation (`startConversation`), accepting an invite (`acceptInvite`), rejecting an invite
78
+ (`rejectInvite`), and leaving a conversation (`leaveConversation`). To track typing indicators,
79
+ you use `startTyping` and `finishSendingMessage`. These are imported from `game/conversations.ts`.
80
+ - Agent inputs are imported from `aiTown/agentInputs.ts` for things like remembering conversations,
81
+ deciding what to do, etc.
82
+
83
+ Each of these inputs' implementation method checks invariants and updates game state as desired.
84
+ For example, the `moveTo` input checks that the player isn't participating in a conversation,
85
+ throwing an error telling them to leave the conversation first if so, and then updates their
86
+ pathfinding state with the desired destination.
87
+
88
+ ### Simulation
89
+
90
+ Other than when processing player inputs, the game state can change over time in the background as the
91
+ simulation runs time forward. For example, if a player has decided to move along a path, their position
92
+ will gradually update as time moves forward. Similarly, if two players collide into each other, they'll
93
+ notice and replan their paths, trying to avoid obstacles.
94
+
95
+ ### Message data model
96
+
97
+ We manage the tables for tracking chat messages in separate tables not affiliated
98
+ with the game engine. This is for a few reasons:
99
+
100
+ - The core simulation doesn't need to know about messages, so keeping them
101
+ out keeps game state small.
102
+ - Messages are updated very frequently (when streamed out from OpenAI) and
103
+ benefit from lower input latency, so they're not a great fit for the engine.
104
+ See "Design goals and limitations" below.
105
+
106
+ Messages (`convex/schema.ts`) are in a conversation and indicate an author and message text.
107
+ Each conversation has a typing state in the conversations table that indicates that a player
108
+ is currently typing. Players can still send messages while another player is typing, but
109
+ having the indicator helps agents (and humans) not talk over each other.
110
+
111
+ The separate tables are queried and modified with regular Convex queries and mutations
112
+ that don't directly go through the simulation.
113
+
114
+ ## Game engine (`convex/engine`)
115
+
116
+ Given the description of AI Town's game behavior in the previous section,
117
+ the `AbstractGame` class in `convex/engine/abstractGame.ts` implements actually running the simulation.
118
+ The game engine has a few responsibilities:
119
+
120
+ - Coordinating incoming player inputs, feeding them into the simulation, and sending their
121
+ return values (or errors) to the client.
122
+ - Running the simulation forward in time.
123
+ - Saving and loading game state from the database.
124
+ - Managing executing the game behavior, efficiently using Convex resources and minimizing input latency.
125
+
126
+ AI Town's game behavior is implemented in the `Game` subclass.
127
+
128
+ ### Input handling
129
+
130
+ Users submit inputs through the `insertInput` function, which inserts them into an `inputs` table, assigning a
131
+ monotonically increasing unique input number and stamping the input with the time the server received it. The
132
+ engine then processes inputs, writing their results back to the `inputs` row. Interested clients can subscribe
133
+ on an input's status with the `inputStatus` query.
134
+
135
+ `Game` provides an abstract method `handleInput` that `AiTown` implements with its specific behavior.
136
+
137
+ ### Running the simulation
138
+
139
+ The `Game` class specifies how it simulates time forward with the `tick` method:
140
+
141
+ - `tick(now)` runs the simulation forward until the given timestamp
142
+ - Ticks are run at a high frequency, configurable with `tickDuration` (milliseconds). Since AI town has smooth motion
143
+ for player movement, it runs at 60 ticks per second.
144
+ - It's generally a good idea to break up game logic into separate systems that can be ticked forward independently.
145
+ For example, AI Town's `tick` method advances pathfinding with `Player.tickPathfinding`, player positions with
146
+ `Player.tickPosition`, conversations with `Conversation.tick`, and `Agent.tick` for agent logic.
147
+
148
+ To avoid running a Convex mutation 60 times per second (which would be expensive and slow), the engine batches up
149
+ many ticks into a _step_. AI town runs steps at only 1 time per second. Here's how a step works:
150
+
151
+ 1. Load the game state into memory.
152
+ 2. Decide how long to run.
153
+ 3. Execute many ticks for our time interval, alternating between feeding in inputs with `handleInput` and advancing
154
+ the simulation with `tick`.
155
+ 4. Write the updated game state back to the database.
156
+
157
+ One core invariant is that the game engine is fully "single-threaded" per world, so there are never two runs of
158
+ an engine's step overlapping in time. Not having to think about race conditions or concurrency makes writing game
159
+ engine code a lot easier.
160
+
161
+ However, preserving this invariant is a little tricky. If the engine is idle for a minute and an
162
+ input comes in, we want to run the engine immediately but then cancel its run after the minute's
163
+ up. If we're not careful, a race condition may cause us to run multiple copies of the engine if an
164
+ input comes in just as an idle timeout is expiring!
165
+
166
+ Our approach is to store a generation number with the engine that monotonically increases over time.
167
+ All scheduled runs of the engine contain their expected generation number as an argument. Then, if
168
+ we'd like to cancel a future run of the engine, we can bump the generation number by one, and then
169
+ we're guaranteed that the subsequent run will fail immediately as it'll notice that the engine's
170
+ generation number does not match its expected one.
171
+
172
+ ### Engine state management
173
+
174
+ The `World`, `Player`, `Conversation`, and `Agent` classes coordinate loading data into memory from the database,
175
+ modifying it according to the game rules, and serializing it to write back out to the database. Here's the flow:
176
+
177
+ 1. The Convex scheduler calls the `convex/aiTown/main.ts:runStep` action.
178
+ 2. The `runStep` action calls `convex/aiTown/game.ts:loadWorld` to load the current game state. This query calls
179
+ `Game.load`, which loads all of a world's game state from the appropriate tables, and returns a
180
+ `GameState` object, which contains serialized versions of all of the players, agents, etc.
181
+ 3. The `runStep` action passes the `GameState` to the `Game` constructor, which parses the serialized versions
182
+ of all our game objects using their constructors. For example, `new Player(serializedPlayer)` parses the
183
+ database representation into the in-memory `Player` class.
184
+ 4. The engine runs the simulation, modifying the in-memory game objects.
185
+ 5. At the end of a step, the framework calls `Game.saveStep`, which computes a diff of the game state since
186
+ the beginning of the step and passes the diff to the `convex/aiTown/game.ts:saveWorld` mutation.
187
+ 6. The `saveWorld` mutation applies the diff to the database, notices if any deleted objects need to be archived,
188
+ updates the `participatedTogether` graph, and kicks off any scheduled jobs to run.
189
+ 7. Since the engine is the only mutator of game state, it continues to run steps for some amount of time
190
+ without repeating steps 1 to 3 again.
191
+
192
+ Just as we assume that the game engine is "single threaded", we also assume that the game engine _exclusively_
193
+ owns the tables that store game engine state. Only the game engine should programmatically modify these tables,
194
+ so components outside the engine can only mutate them by sending inputs.
195
+
196
+ ### Historical tables
197
+
198
+ If we're only writing updates out to the database at the end of the step, and steps are only running at once per
199
+ second, continuous quantities like position will only update every second. This, then, defeats the whole purpose
200
+ of having high-frequency ticks: Player positions will jump around and look choppy.
201
+
202
+ To solve this, we track the historical values of quantities like position _within_ a step, storing the value
203
+ at the end of each tick. Then, the client receives both the current value _and_ the past step's worth of
204
+ history, and it can "replay" the history to make the motion smooth.
205
+
206
+ The game tracks these quantities at the end of each tick by feeding them to a `HistoricalObject`. This object
207
+ efficiently tracks its changes over time and serializes them into a buffer that clients can use for replaying
208
+ its history. There are a few limitations on `HistoricalObject`:
209
+
210
+ - Historical objects can only have numeric (floating point) values and can't have nested objects or optional fields.
211
+ - Historical objects must declare which fields they'd like to track.
212
+
213
+ We store each player's "location" (i.e. its position, orientation, and speed) in a `HistoricalObject` and
214
+ write it to the `worlds` document at the end of a step when computing a diff.
215
+
216
+ ## Client-side game UI (`src/`)
217
+
218
+ One guiding principle for AI Town's architecture is to keep the usage as close to "regular Convex" usage as possible. So,
219
+ game state is stored in regular tables, and the UI just uses regular `useQuery` hooks to load that state and render
220
+ it in the UI.
221
+
222
+ The one exception is for historical tables, which feed in the latest state into a `useHistoricalValue` hook that parses
223
+ the history buffer and replays time forward for smooth motion. To keep replayed time synchronized across multiple
224
+ historical buffers, we provide a `useHistoricalTime` hook for the top of your app that keeps track of the current
225
+ time and returns it for you to pass down into components.
226
+
227
+ We also provide a `useSendInput` hook that wraps `useMutation` and automatically sends inputs to the server and
228
+ waits for the engine to process them and return their outcome.
229
+
230
+ ## Agent architecture (`convex/agent`)
231
+
232
+ ### The agent loop (`convex/game/agents.ts`)
233
+
234
+ Agents will execute any game state changes, and schedule operations to do anything that requires
235
+ a long-lived request or accessing non-game tables. The flow generally is:
236
+
237
+ 1. Logic in `Agent.tick` can read and modify game state as time progresses, such as waiting until
238
+ the agent is near another player to start talking.
239
+ 2. When there is something that needs to talk to an LLM or read/write external data,
240
+ it calls `startOperation` with a reference to a Convex function: generally an `internalAction`.
241
+ 3. This function can read state from game tables and other tables via `internalQuery` functions.
242
+ 4. It executes long-running tasks, and can write data via `internalMutation`s.
243
+ Game state should not be written, but rather submitted via `inputs` (described in a previous section).
244
+ 5. Inputs are submitted from actions with `ctx.runMutation(api.game.main.sendInput, {...})` from actions
245
+ or via `insertInput` from mutations. They are referenced by their name as a string, like `moveTo`.
246
+ 6. Inputs are defined with `inputHandler` and are given an instance of the AiTown game to modify,
247
+ similar to the game loop. In fact, these are called as part of the game loop before `tickAgent`.
248
+ 7. When an operation is done, it deletes the `inProgressOperation`. This is to ensure an agent only
249
+ is trying to do one thing at a time.
250
+ 8. `Agent.tick` then can observe the new game state and continue to make decisions.
251
+
252
+ ### Conversations (`convex/agent/conversations.ts`)
253
+
254
+ The agent code calls into the conversation layer which implements the prompt engineering for
255
+ injecting personality and memories into the GPT responses. It has functions for starting a
256
+ conversation (`startConversation`), continuing after the first message (`continueConversation`), and
257
+ politely leaving a conversation (`leaveConversation`). Each function loads structured data from the
258
+ database, queries the memory layer for the agent's opinion about the player they're talking with,
259
+ and then calls into the OpenAI client (`convex/util/openai.ts`).
260
+
261
+ ### Memories (`convex/agent/memory.ts`)
262
+
263
+ After each conversation, GPT summarizes its message history, and we compute an embedding of the
264
+ summary text and write it into Convex's vector database. Then, when starting a new conversation
265
+ with, Danny, we embed "What you think about Danny?", find the three most similar memories, and fetch
266
+ their summary texts to inject into the conversation prompt.
267
+
268
+ ### Embeddings cache (`convex/agent/embeddingsCache.ts`)
269
+
270
+ To avoid computing the same embedding over and over again, we cache embeddings by a hash of their
271
+ text in a Convex table.
272
+
273
+ ## Design goals and limitations
274
+
275
+ AI Town's game engine has a few design goals:
276
+
277
+ - Try to be as close to a regular Convex app as possible. Use regular client hooks (like `useQuery`)
278
+ when possible, and store game state in regular tables.
279
+ - Be as similar to existing engines as possible, so it's easy to change the behavior. We chose a
280
+ `tick()` based model for simulation since it's commonly used elsewhere and intuitive.
281
+ - Decouple agent behavior from the game engine. It's nice to allow human players and AI agents to do
282
+ all the same things in the game.
283
+
284
+ These design goals imply some inherent limitations:
285
+
286
+ - All data is loaded into memory each step. The active game state loaded by the game should be small
287
+ enough to fit into memory and load and save frequently. Try to keep game state to less than a few dozen
288
+ kilobytes: Games that require tens of thousands of objects interacting together may not be a good
289
+ fit.
290
+ - All inputs are fed through the database in the `inputs` table, so applications that require very
291
+ large or frequent inputs may not be a good fit.
292
+ - Input latency will be around one RTT (time for the input to make it to the server and the response
293
+ to come back) plus half the step size (for expected server input delay when the input's waiting
294
+ for the next step). Historical values add another half step size of input latency since their
295
+ values are viewed slightly in the past. As configured, this will roughly be around 1.5s of input
296
+ latency, which won't be a good fit for competitive games. You can configure the step size to be
297
+ smaller (e.g. 250ms) which will decrease input latency at the cost of adding more Convex function
298
+ calls and database bandwidth.
299
+ - The game engine is designed to be single threaded. JavaScript operating over plain objects
300
+ in-memory can be surprisingly fast, but if your simulation is very computationally expensive, it
301
+ may not be a good fit on AI Town's engine today.
Dockerfile CHANGED
@@ -17,10 +17,6 @@ ENV HOME=/home/user \
17
  PATH=/home/user/.local/bin:$PATH
18
 
19
  WORKDIR $HOME/app
20
-
21
- RUN git clone https://github.com/a16z-infra/ai-town.git . && \
22
- git checkout f005c46d1759b47bb3ade8d41952a713c4faf331
23
-
24
  RUN npm install --include=dev @huggingface/inference
25
  RUN npm install --include=dev @huggingface/hub
26
 
@@ -28,17 +24,4 @@ RUN npm install --include=dev @huggingface/hub
28
  RUN curl -L -O https://github.com/get-convex/convex-backend/releases/download/precompiled-2024-05-07-13337fd/convex-local-backend-x86_64-unknown-linux-gnu.zip && \
29
  unzip convex-local-backend-x86_64-unknown-linux-gnu.zip
30
 
31
- COPY ./patches ./
32
- COPY ./patches/vite.config.ts ./
33
- COPY ./patches/characters.ts ./patches/gentle.js ./data/
34
- COPY ./patches/run.sh ./
35
-
36
- COPY ./map.png ./assets/map.png
37
- COPY ./patches/assets/GrayCat.png ./assets/GrayCat.png
38
- COPY ./patches/assets/OrangeCat.png ./assets/OrangeCat.png
39
- COPY ./patches/assets/hf.svg ./assets/hf.svg
40
- COPY ./patches/data/spritesheets/c1.ts ./data/spritesheets/c1.ts
41
-
42
-
43
-
44
  CMD ["./run.sh"]
 
17
  PATH=/home/user/.local/bin:$PATH
18
 
19
  WORKDIR $HOME/app
 
 
 
 
20
  RUN npm install --include=dev @huggingface/inference
21
  RUN npm install --include=dev @huggingface/hub
22
 
 
24
  RUN curl -L -O https://github.com/get-convex/convex-backend/releases/download/precompiled-2024-05-07-13337fd/convex-local-backend-x86_64-unknown-linux-gnu.zip && \
25
  unzip convex-local-backend-x86_64-unknown-linux-gnu.zip
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  CMD ["./run.sh"]
Justfile ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ set fallback := true
2
+ set shell := ["bash", "-uc"]
3
+ set windows-shell := ["sh", "-uc"]
4
+
5
+ # `just --list` (or just `just`) will print all the recipes in
6
+ # the current Justfile. `just RECIPE` will run the macro/job.
7
+ #
8
+ # In several places there are recipes for running common scripts or commands.
9
+ # Instead of `Makefile`s, Convex uses Justfiles, which are similar, but avoid
10
+ # several footguns associated with Makefiles, since using make as a macro runner
11
+ # can sometimes conflict with Makefiles desire to have some rudimentary
12
+ # understanding of build artifacts and associated dependencies.
13
+ #
14
+ # Read up on just here: https://github.com/casey/just
15
+
16
+ _default:
17
+ @just --list
18
+
19
+ set positional-arguments
20
+
21
+ # Uses an admin key from admin_key.txt for dev backends.
22
+ # This uses the default admin key for local backends, which is safe as long as the backend is
23
+ # running locally.
24
+ # (*) Run convex CLI commands like `convex dev` against local backend from `just run-local-backend`.
25
+ convex *ARGS:
26
+ cd {{invocation_directory()}}; npx convex "$@" --admin-key 0135d8598650f8f5cb0f30c34ec2e2bb62793bc28717c8eb6fb577996d50be5f4281b59181095065c5d0f86a2c31ddbe9b597ec62b47ded69782cd --url "http://127.0.0.1:3210"
27
+
28
+ # Clears any data or stored files from the local backend.
29
+ reset-local-backend:
30
+ rm -rf convex_local_storage && rm -f convex_local_backend.sqlite3
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2023 a16z-infra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,36 +1,445 @@
1
- ---
2
- title: AI Town on HuggingFace
3
- emoji: πŸ πŸˆβ€β¬›
4
- colorFrom: green
5
- colorTo: red
6
- sdk: docker
7
- app_port: 5173
8
- pinned: false
9
- disable_embedding: true
10
- # header: mini
11
- short_description: AI Town on HuggingFace
12
- hf_oauth: true
13
- ---
14
 
15
- # AI Town πŸ πŸ’»πŸ’Œ on Hugging Face πŸ€—
16
 
17
- [**Demo on Hugging Face Spaces**](https://huggingface.co/spaces/radames/ai-town)
18
 
19
- AI Town is a very cool project by [Yoko](https://github.com/ykhli) et [al.](https://github.com/a16z-infra/ai-town), a virtual town with live AI characters where they can chat and socialize. You can also interact with them by sending them messages.
20
 
21
- This repository contains a few code patches to make AI Town run on [Hugging Face πŸ€— Spaces](https://huggingface.co/spaces), as well as a Dockerfile capable of running [Convex open-source backend](https://github.com/get-convex/convex-backend), the backend and frontend on a single container.
22
 
23
- ## How to run locally
 
24
 
25
- Grab your Hugging Face API token from https://huggingface.co/settings/tokens
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  ```bash
28
- export HF_TOKEN=hf_**********
29
- docker build -t ai-town -f Dockerfile .
30
- docker run -ti -p 5173:5173 -e LLM_API_KEY=$HF_TOKEN ai-town
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  ```
32
 
33
- ## How to run on Hugging Face
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- You can duplicate this Space https://huggingface.co/spaces/radames/ai-town?duplicate=true, add your `HF_TOKEN`
36
- Then you can customize [patches/constants.ts](patches/constants.ts) and [patches/characters.ts](patches/characters.ts) as you wish, as well as the LLM model and embeddings model in [patches/llm.ts](patches/llm.ts).
 
1
+ # AI Town πŸ πŸ’»πŸ’Œ
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ [Live Demo](https://www.convex.dev/ai-town)
4
 
5
+ [Join our community Discord: AI Stack Devs](https://discord.gg/PQUmTBTGmT)
6
 
7
+ <img width="1454" alt="Screen Shot 2023-08-14 at 10 01 00 AM" src="https://github.com/a16z-infra/ai-town/assets/3489963/a4c91f17-23ed-47ec-8c4e-9f9a8505057d">
8
 
9
+ AI Town is a virtual town where AI characters live, chat and socialize.
10
 
11
+ This project is a deployable starter kit for easily building and customizing your own version of AI town.
12
+ Inspired by the research paper [_Generative Agents: Interactive Simulacra of Human Behavior_](https://arxiv.org/pdf/2304.03442.pdf).
13
 
14
+ The primary goal of this project, beyond just being a lot of fun to work on,
15
+ is to provide a platform with a strong foundation that is meant to be extended.
16
+ The back-end natively supports shared global state, transactions, and a simulation engine
17
+ and should be suitable from everything from a simple project to play around with to a scalable, multi-player game.
18
+ A secondary goal is to make a JS/TS framework available as most simulators in this space
19
+ (including the original paper above) are written in Python.
20
+
21
+ ## Overview
22
+
23
+ - πŸ’» [Stack](#stack)
24
+ - 🧠 [Installation](#installation)
25
+ - πŸ‘€ [Customize - run YOUR OWN simulated world](#customize-your-own-simulation)
26
+ - πŸ‘©β€πŸ’» [Deploying](#deploy-the-app)
27
+ - πŸ† [Credits](#credits)
28
+
29
+ ## Stack
30
+
31
+ - Game engine, database, and vector search: [Convex](https://convex.dev/)
32
+ - Auth (Optional): [Clerk](https://clerk.com/)
33
+ - Default chat model is `llama3` and embeddings with `mxbai-embed-large`.
34
+ - Local inference: [Ollama](https://github.com/jmorganca/ollama)
35
+ - Configurable for other cloud LLMs: [Together.ai](https://together.ai/) or anything
36
+ that speaks the [OpenAI API](https://platform.openai.com/).
37
+ PRs welcome to add more cloud provider support.
38
+ - Pixel Art Generation: [Replicate](https://replicate.com/), [Fal.ai](https://serverless.fal.ai/lora)
39
+ - Background Music Generation: [Replicate](https://replicate.com/) using [MusicGen](https://huggingface.co/spaces/facebook/MusicGen)
40
+
41
+ ## Installation
42
+
43
+ **Note**: There is a one-click install of a fork of this project on
44
+ [Pinokio](https://pinokio.computer/item?uri=https://github.com/cocktailpeanutlabs/aitown)
45
+ for anyone interested in running but not modifying it 😎
46
+
47
+ ### 1. Clone repo and Install packages
48
+
49
+ ```bash
50
+ git clone https://github.com/a16z-infra/ai-town.git
51
+ cd ai-town
52
+ npm install
53
+ ```
54
+
55
+ ### 2. To develop locally with [Convex](https://convex.dev):
56
+
57
+ Either
58
+ [download a pre-built binary(recommended)](https://github.com/get-convex/convex-backend/releases),
59
+ or [build it from source and run it](https://stack.convex.dev/building-the-oss-backend).
60
+
61
+ ```sh
62
+ # For new Macs:
63
+ curl -L -O https://github.com/get-convex/convex-backend/releases/latest/download/convex-local-backend-aarch64-apple-darwin.zip
64
+ unzip convex-local-backend-aarch64-apple-darwin.zip
65
+
66
+ brew install just
67
+
68
+ # Runs the server
69
+ ./convex-local-backend
70
+ ```
71
+
72
+ This also [installs `just`](https://github.com/casey/just?tab=readme-ov-file#installation)
73
+ (e.g. `brew install just` or `cargo install just`).
74
+ We use `just` like `make` to add extra params, so you run `just convex ...`
75
+ instead of `npx convex ...` for local development.
76
+
77
+ If you're running the pre-built binary on Mac and there's an Apple warning,
78
+ go to the folder it's in and right-click it and select "Open" to bypass.
79
+ From then on you can run it from the commandline.
80
+ Or you can compile it from source and run it (see above).
81
+
82
+ To develop against the cloud-hosted version, change the package.json scripts
83
+ to use `convex ...` instead of `just convex ...`.
84
+
85
+ ### 3. To run a local LLM, download and run [Ollama](https://ollama.com/).
86
+
87
+ You can leave the app running or run `ollama serve`.
88
+ `ollama serve` will warn you if the app is already running.
89
+ Run `ollama pull llama3` to have it download `llama3`.
90
+ Test it out with `ollama run llama3`.
91
+ If you want to customize which model to use, adjust convex/util/llm.ts or set
92
+ `just convex env set LLM_MODEL # model`.
93
+ Ollama model options can be found [here](https://ollama.ai/library).
94
+
95
+ You might want to set `NUM_MEMORIES_TO_SEARCH` to `1` in constants.ts,
96
+ to reduce the size of conversation prompts, if you see slowness.
97
+
98
+ Check out `convex/config.ts` to configure which models to offer to the UI,
99
+ or to set it up to talk to a cloud-hosted LLM.
100
+
101
+ ### 4. Adding background music with Replicate (Optional)
102
+
103
+ For Daily background music generation, create a
104
+ [Replicate](https://replicate.com/) account and create a token in your Profile's
105
+ [API Token page](https://replicate.com/account/api-tokens).
106
+ `npx convex env set REPLICATE_API_TOKEN # token`
107
+ Specify `just` instead of `npx` if you're doing local development.
108
+
109
+ ### 5. Run the code
110
+
111
+ To run both the front and and back end:
112
+
113
+ ```bash
114
+ npm run dev
115
+ ```
116
+
117
+ **Note**: If you encounter a node version error on the convex server upon application startup, please use node version 18, which is the most stable. One way to do this is by [installing nvm](https://nodejs.org/en/download/package-manager) and running `nvm install 18` or `nvm use 18`. Do this before both the `npm run dev` above and the `./convex-local-backend` in Step 2.
118
+
119
+ You can now visit http://localhost:5173.
120
+
121
+ If you'd rather run the frontend in a separate terminal from Convex (which syncs
122
+ your backend functions as they're saved), you can run these two commands:
123
+
124
+ ```bash
125
+ npm run dev:frontend
126
+ npm run dev:backend
127
+ ```
128
+
129
+ See package.json for details, but dev:backend runs `just convex dev`
130
+
131
+ **Note**: The simulation will pause after 5 minutes if the window is idle.
132
+ Loading the page will unpause it.
133
+ You can also manually freeze & unfreeze the world with a button in the UI.
134
+ If you want to run the world without the
135
+ browser, you can comment-out the "stop inactive worlds" cron in `convex/crons.ts`.
136
+
137
+ ### Various commands to run / test / debug
138
+
139
+ **To stop the back end, in case of too much activity**
140
+
141
+ This will stop running the engine and agents. You can still run queries and
142
+ run functions to debug.
143
+
144
+ ```bash
145
+ just convex run testing:stop
146
+ ```
147
+
148
+ **To restart the back end after stopping it**
149
+
150
+ ```bash
151
+ just convex run testing:resume
152
+ ```
153
+
154
+ **To kick the engine in case the game engine or agents aren't running**
155
+
156
+ ```bash
157
+ just convex run testing:kick
158
+ ```
159
+
160
+ **To archive the world**
161
+
162
+ If you'd like to reset the world and start from scratch, you can archive the current world:
163
 
164
  ```bash
165
+ just convex run testing:archive
166
+ ```
167
+
168
+ Then, you can still look at the world's data in the dashboard, but the engine and agents will
169
+ no longer run.
170
+
171
+ You can then create a fresh world with `init`.
172
+
173
+ ```bash
174
+ just convex run init
175
+ ```
176
+
177
+ **To clear all databases**
178
+
179
+ You can wipe all tables with the `wipeAllTables` testing function.
180
+
181
+ ```bash
182
+ just convex run testing:wipeAllTables
183
+ ```
184
+
185
+ **To pause your backend deployment**
186
+
187
+ You can go to the [dashboard](https://dashboard.convex.dev) to your deployment
188
+ settings to pause and un-pause your deployment. This will stop all functions, whether invoked
189
+ from the client, scheduled, or as a cron job. See this as a last resort, as
190
+ there are gentler ways of stopping above. Once you
191
+
192
+ ## Customize your own simulation
193
+
194
+ NOTE: every time you change character data, you should re-run
195
+ `just convex run testing:wipeAllTables` and then
196
+ `npm run dev` to re-upload everything to Convex.
197
+ This is because character data is sent to Convex on the initial load.
198
+ However, beware that `just convex run testing:wipeAllTables` WILL wipe all of your data.
199
+
200
+ 1. Create your own characters and stories: All characters and stories, as well as their spritesheet references are stored in [characters.ts](./data/characters.ts). You can start by changing character descriptions.
201
+
202
+ 2. Updating spritesheets: in `data/characters.ts`, you will see this code:
203
+
204
+ ```ts
205
+ export const characters = [
206
+ {
207
+ name: 'f1',
208
+ textureUrl: '/assets/32x32folk.png',
209
+ spritesheetData: f1SpritesheetData,
210
+ speed: 0.1,
211
+ },
212
+ ...
213
+ ];
214
  ```
215
 
216
+ You should find a sprite sheet for your character, and define sprite motion / assets in the corresponding file (in the above example, `f1SpritesheetData` was defined in f1.ts)
217
+
218
+ 3. Update the Background (Environment): The map gets loaded in `convex/init.ts` from `data/gentle.js`. To update the map, follow these steps:
219
+
220
+ - Use [Tiled](https://www.mapeditor.org/) to export tilemaps as a JSON file (2 layers named bgtiles and objmap)
221
+ - Use the `convertMap.js` script to convert the JSON to a format that the engine can use.
222
+
223
+ ```console
224
+ node data/convertMap.js <mapDataPath> <assetPath> <tilesetpxw> <tilesetpxh>
225
+ ```
226
+
227
+ - `<mapDataPath>`: Path to the Tiled JSON file.
228
+ - `<assetPath>`: Path to tileset images.
229
+ - `<tilesetpxw>`: Tileset width in pixels.
230
+ - `<tilesetpxh>`: Tileset height in pixels.
231
+ Generates `converted-map.js` that you can use like `gentle.js`
232
+
233
+ 4. Change the background music by modifying the prompt in `convex/music.ts`
234
+ 5. Change how often to generate new music at `convex/crons.ts` by modifying the `generate new background music` job
235
+
236
+ ## Using a cloud AI Provider
237
+
238
+ Configure `convex/util/llm.ts` or set these env variables:
239
+
240
+ ```sh
241
+ # Local Convex
242
+ just convex env set LLM_API_HOST # url
243
+ just convex env set LLM_MODEL # model
244
+ # Cloud Convex
245
+ npx convex env set LLM_API_HOST # url
246
+ npx convex env set LLM_MODEL # model
247
+ ```
248
+
249
+ The embeddings model config needs to be changed [in code](./convex/util/llm.ts),
250
+ since you need to specify the embeddings dimension.
251
+
252
+ ### Keys
253
+
254
+ For Together.ai, visit https://api.together.xyz/settings/api-keys
255
+ For OpenAI, visit https://platform.openai.com/account/api-keys
256
+
257
+ ## Using hosted Convex
258
+
259
+ You can run your Convex backend in the cloud by just running
260
+
261
+ ```sh
262
+ npx convex dev --once --configure
263
+ ```
264
+
265
+ And updating the `package.json` scripts to remove `just`:
266
+ change `just convex ...` to `convex ...`.
267
+
268
+ You'll then need to set any environment variables you had locally in the cloud
269
+ environment with `npx convex env set` or on the dashboard:
270
+ https://dashboard.convex.dev/deployment/settings/environment-variables
271
+
272
+ To run commands, use `npx convex ...` where you used to run `just convex ...`.
273
+
274
+ ## Deploy the app
275
+
276
+ ### Deploy Convex functions to prod environment
277
+
278
+ Before you can run the app, you will need to make sure the Convex functions are deployed to its production environment.
279
+
280
+ 1. Run `npx convex deploy` to deploy the convex functions to production
281
+ 2. Run `npx convex run init --prod`
282
+
283
+ If you have existing data you want to clear, you can run `npx convex run testing:wipeAllTables --prod`
284
+
285
+ ### Adding Auth (Optional)
286
+
287
+ You can add clerk auth back in with `git revert b44a436`.
288
+ Or just look at that diff for what changed to remove it.
289
+
290
+ **Make a Clerk account**
291
+
292
+ - Go to https://dashboard.clerk.com/ and click on "Add Application"
293
+ - Name your application and select the sign-in providers you would like to offer users
294
+ - Create Application
295
+ - Add `VITE_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` to `.env.local`
296
+
297
+ ```bash
298
+ VITE_CLERK_PUBLISHABLE_KEY=pk_***
299
+ CLERK_SECRET_KEY=sk_***
300
+ ```
301
+
302
+ - Go to JWT Templates and create a new Convex Template.
303
+ - Copy the JWKS endpoint URL for use below.
304
+
305
+ ```sh
306
+ npx convex env set CLERK_ISSUER_URL # e.g. https://your-issuer-url.clerk.accounts.dev/
307
+ ```
308
+
309
+ ### Deploy to Vercel
310
+
311
+ - Register an account on Vercel and then [install the Vercel CLI](https://vercel.com/docs/cli).
312
+ - **If you are using Github Codespaces**: You will need to [install the Vercel CLI](https://vercel.com/docs/cli) and authenticate from your codespaces cli by running `vercel login`.
313
+ - Deploy the app to Vercel with `vercel --prod`.
314
+
315
+ ## Using local inference from a cloud deployment.
316
+
317
+ We support using [Ollama](https://github.com/jmorganca/ollama) for conversation generations.
318
+ To have it accessible from the web, you can use Tunnelmole or Ngrok or similar.
319
+
320
+ **Using Tunnelmole**
321
+
322
+ [Tunnelmole](https://github.com/robbie-cahill/tunnelmole-client) is an open source tunneling tool.
323
+
324
+ You can install Tunnelmole using one of the following options:
325
+
326
+ - NPM: `npm install -g tunnelmole`
327
+ - Linux: `curl -s https://tunnelmole.com/sh/install-linux.sh | sudo bash`
328
+ - Mac: `curl -s https://tunnelmole.com/sh/install-mac.sh --output install-mac.sh && sudo bash install-mac.sh`
329
+ - Windows: Install with NPM, or if you don't have NodeJS installed, download the `exe` file for Windows [here](https://tunnelmole.com/downloads/tmole.exe) and put it somewhere in your PATH.
330
+
331
+ Once Tunnelmole is installed, run the following command:
332
+
333
+ ```
334
+ tmole 11434
335
+ ```
336
+
337
+ Tunnelmole should output a unique url once you run this command.
338
+
339
+ **Using Ngrok**
340
+
341
+ Ngrok is a popular closed source tunneling tool.
342
+
343
+ - [Install Ngrok](https://ngrok.com/docs/getting-started/)
344
+
345
+ Once ngrok is installed and authenticated, run the following command:
346
+
347
+ ```
348
+ ngrok http http://localhost:11434
349
+ ```
350
+
351
+ Ngrok should output a unique url once you run this command.
352
+
353
+ **Add Ollama endpoint to Convex**
354
+
355
+ ```sh
356
+ npx convex env set OLLAMA_HOST # your tunnelmole/ngrok unique url from the previous step
357
+ ```
358
+
359
+ **Update Ollama domains**
360
+
361
+ Ollama has a list of accepted domains. Add the ngrok domain so it won't reject
362
+ traffic. see ollama.ai for more details.
363
+
364
+ ## Credits
365
+
366
+ - All interactions, background music and rendering on the <Game/> component in the project are powered by [PixiJS](https://pixijs.com/).
367
+ - Tilesheet:
368
+ - https://opengameart.org/content/16x16-game-assets by George Bailey
369
+ - https://opengameart.org/content/16x16-rpg-tileset by hilau
370
+ - We used https://github.com/pierpo/phaser3-simple-rpg for the original POC of this project. We have since re-wrote the whole app, but appreciated the easy starting point
371
+ - Original assets by [ansimuz](https://opengameart.org/content/tiny-rpg-forest)
372
+ - The UI is based on original assets by [Mounir Tohami](https://mounirtohami.itch.io/pixel-art-gui-elements)
373
+
374
+ # πŸ§‘β€πŸ« What is Convex?
375
+
376
+ [Convex](https://convex.dev) is a hosted backend platform with a
377
+ built-in database that lets you write your
378
+ [database schema](https://docs.convex.dev/database/schemas) and
379
+ [server functions](https://docs.convex.dev/functions) in
380
+ [TypeScript](https://docs.convex.dev/typescript). Server-side database
381
+ [queries](https://docs.convex.dev/functions/query-functions) automatically
382
+ [cache](https://docs.convex.dev/functions/query-functions#caching--reactivity) and
383
+ [subscribe](https://docs.convex.dev/client/react#reactivity) to data, powering a
384
+ [realtime `useQuery` hook](https://docs.convex.dev/client/react#fetching-data) in our
385
+ [React client](https://docs.convex.dev/client/react). There are also clients for
386
+ [Python](https://docs.convex.dev/client/python),
387
+ [Rust](https://docs.convex.dev/client/rust),
388
+ [ReactNative](https://docs.convex.dev/client/react-native), and
389
+ [Node](https://docs.convex.dev/client/javascript), as well as a straightforward
390
+ [HTTP API](https://docs.convex.dev/http-api/).
391
+
392
+ The database supports
393
+ [NoSQL-style documents](https://docs.convex.dev/database/document-storage) with
394
+ [opt-in schema validation](https://docs.convex.dev/database/schemas),
395
+ [relationships](https://docs.convex.dev/database/document-ids) and
396
+ [custom indexes](https://docs.convex.dev/database/indexes/)
397
+ (including on fields in nested objects).
398
+
399
+ The
400
+ [`query`](https://docs.convex.dev/functions/query-functions) and
401
+ [`mutation`](https://docs.convex.dev/functions/mutation-functions) server functions have transactional,
402
+ low latency access to the database and leverage our
403
+ [`v8` runtime](https://docs.convex.dev/functions/runtimes) with
404
+ [determinism guardrails](https://docs.convex.dev/functions/runtimes#using-randomness-and-time-in-queries-and-mutations)
405
+ to provide the strongest ACID guarantees on the market:
406
+ immediate consistency,
407
+ serializable isolation, and
408
+ automatic conflict resolution via
409
+ [optimistic multi-version concurrency control](https://docs.convex.dev/database/advanced/occ) (OCC / MVCC).
410
+
411
+ The [`action` server functions](https://docs.convex.dev/functions/actions) have
412
+ access to external APIs and enable other side-effects and non-determinism in
413
+ either our
414
+ [optimized `v8` runtime](https://docs.convex.dev/functions/runtimes) or a more
415
+ [flexible `node` runtime](https://docs.convex.dev/functions/runtimes#nodejs-runtime).
416
+
417
+ Functions can run in the background via
418
+ [scheduling](https://docs.convex.dev/scheduling/scheduled-functions) and
419
+ [cron jobs](https://docs.convex.dev/scheduling/cron-jobs).
420
+
421
+ Development is cloud-first, with
422
+ [hot reloads for server function](https://docs.convex.dev/cli#run-the-convex-dev-server) editing via the
423
+ [CLI](https://docs.convex.dev/cli),
424
+ [preview deployments](https://docs.convex.dev/production/hosting/preview-deployments),
425
+ [logging and exception reporting integrations](https://docs.convex.dev/production/integrations/),
426
+ There is a
427
+ [dashboard UI](https://docs.convex.dev/dashboard) to
428
+ [browse and edit data](https://docs.convex.dev/dashboard/deployments/data),
429
+ [edit environment variables](https://docs.convex.dev/production/environment-variables),
430
+ [view logs](https://docs.convex.dev/dashboard/deployments/logs),
431
+ [run server functions](https://docs.convex.dev/dashboard/deployments/functions), and more.
432
+
433
+ There are built-in features for
434
+ [reactive pagination](https://docs.convex.dev/database/pagination),
435
+ [file storage](https://docs.convex.dev/file-storage),
436
+ [reactive text search](https://docs.convex.dev/text-search),
437
+ [vector search](https://docs.convex.dev/vector-search),
438
+ [https endpoints](https://docs.convex.dev/functions/http-actions) (for webhooks),
439
+ [snapshot import/export](https://docs.convex.dev/database/import-export/),
440
+ [streaming import/export](https://docs.convex.dev/production/integrations/streaming-import-export), and
441
+ [runtime validation](https://docs.convex.dev/database/schemas#validators) for
442
+ [function arguments](https://docs.convex.dev/functions/args-validation) and
443
+ [database data](https://docs.convex.dev/database/schemas#schema-validation).
444
 
445
+ Everything scales automatically, and it’s [free to start](https://www.convex.dev/plans).
 
README.md.yml DELETED
@@ -1,18 +0,0 @@
1
- title: AI Town on HuggingFace
2
- emoji: πŸ πŸ’»πŸ’ŒπŸ€—
3
- colorFrom: green
4
- colorTo: red
5
- sdk: docker
6
- app_port: 5173
7
- pinned: false
8
- disable_embedding: true
9
- # header: mini
10
- short_description: AI Town on HuggingFace
11
- hf_oauth: true
12
- # optional, default duration is 8 hours/480 minutes. Max duration is 30 days/43200 minutes.
13
- hf_oauth_expiration_minutes: 480
14
- # optional, see "Scopes" below. "openid profile" is always included.
15
- hf_oauth_scopes:
16
- - read-repos
17
- - manage-repos
18
- - inference-api
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{patches/assets β†’ assets}/32x32folk.png RENAMED
File without changes
{patches/assets β†’ assets}/GrayCat.png RENAMED
File without changes
{patches/assets β†’ assets}/OrangeCat.png RENAMED
File without changes
{patches/assets β†’ assets}/a16z.png RENAMED
File without changes
{patches/assets β†’ assets}/background.webp RENAMED
File without changes
{patches/assets β†’ assets}/close.svg RENAMED
File without changes
{patches/assets β†’ assets}/cloud.jpg RENAMED
File without changes
{patches/assets β†’ assets}/convex-bg.webp RENAMED
File without changes
{patches/assets β†’ assets}/convex.svg RENAMED
File without changes
{patches/assets β†’ assets}/favicon.ico RENAMED
File without changes
{patches/assets β†’ assets}/fonts/upheaval_pro.ttf RENAMED
File without changes
{patches/assets β†’ assets}/fonts/vcr_osd_mono.ttf RENAMED
File without changes
{patches/assets β†’ assets}/heart-empty.png RENAMED
File without changes
{patches/assets β†’ assets}/help.svg RENAMED
File without changes
{patches/assets β†’ assets}/hf.svg RENAMED
File without changes
{patches/assets β†’ assets}/interact.svg RENAMED
File without changes
{patches/assets β†’ assets}/magecity.png RENAMED
File without changes
map.png β†’ assets/map.png RENAMED
File without changes
{patches/assets β†’ assets}/map_night.png RENAMED
File without changes
{patches/assets β†’ assets}/player.png RENAMED
File without changes
{patches/assets β†’ assets}/rpg-tileset.png RENAMED
File without changes
{patches/assets β†’ assets}/spritesheets/campfire.png RENAMED
File without changes
{patches/assets β†’ assets}/spritesheets/gentlesparkle32.png RENAMED
File without changes
{patches/assets β†’ assets}/spritesheets/gentlewaterfall32.png RENAMED
File without changes
{patches/assets β†’ assets}/spritesheets/windmill.png RENAMED
File without changes
{patches/assets β†’ assets}/star.svg RENAMED
File without changes
{patches/assets β†’ assets}/tilemap.json RENAMED
File without changes
{patches/assets β†’ assets}/ui/box.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/bubble-left.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/bubble-right.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/button.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/button_pressed.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/chats.svg RENAMED
File without changes
{patches/assets β†’ assets}/ui/desc.svg RENAMED
File without changes