@koi-language/koi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/QUICKSTART.md +89 -0
  2. package/README.md +545 -0
  3. package/examples/actions-demo.koi +177 -0
  4. package/examples/cache-test.koi +29 -0
  5. package/examples/calculator.koi +61 -0
  6. package/examples/clear-registry.js +33 -0
  7. package/examples/clear-registry.koi +30 -0
  8. package/examples/code-introspection-test.koi +149 -0
  9. package/examples/counter.koi +132 -0
  10. package/examples/delegation-test.koi +52 -0
  11. package/examples/directory-import-test.koi +84 -0
  12. package/examples/hello-world-claude.koi +52 -0
  13. package/examples/hello-world.koi +52 -0
  14. package/examples/hello.koi +24 -0
  15. package/examples/mcp-example.koi +70 -0
  16. package/examples/multi-event-handler-test.koi +144 -0
  17. package/examples/new-import-test.koi +89 -0
  18. package/examples/pipeline.koi +162 -0
  19. package/examples/registry-demo.koi +184 -0
  20. package/examples/registry-playbook-demo.koi +162 -0
  21. package/examples/registry-playbook-email-compositor-2.koi +140 -0
  22. package/examples/registry-playbook-email-compositor.koi +140 -0
  23. package/examples/sentiment.koi +90 -0
  24. package/examples/simple.koi +48 -0
  25. package/examples/skill-import-test.koi +76 -0
  26. package/examples/skills/advanced/index.koi +95 -0
  27. package/examples/skills/math-operations.koi +69 -0
  28. package/examples/skills/string-operations.koi +56 -0
  29. package/examples/task-chaining-demo.koi +244 -0
  30. package/examples/test-await.koi +22 -0
  31. package/examples/test-crypto-sha256.koi +196 -0
  32. package/examples/test-delegation.koi +41 -0
  33. package/examples/test-multi-team-routing.koi +258 -0
  34. package/examples/test-no-handler.koi +35 -0
  35. package/examples/test-npm-import.koi +67 -0
  36. package/examples/test-parse.koi +10 -0
  37. package/examples/test-peers-with-team.koi +59 -0
  38. package/examples/test-permissions-fail.koi +20 -0
  39. package/examples/test-permissions.koi +36 -0
  40. package/examples/test-simple-registry.koi +31 -0
  41. package/examples/test-typescript-import.koi +64 -0
  42. package/examples/test-uses-team-syntax.koi +25 -0
  43. package/examples/test-uses-team.koi +31 -0
  44. package/examples/utils/calculator.test.ts +144 -0
  45. package/examples/utils/calculator.ts +56 -0
  46. package/examples/utils/math-helpers.js +50 -0
  47. package/examples/utils/math-helpers.ts +55 -0
  48. package/examples/web-delegation-demo.koi +165 -0
  49. package/package.json +78 -0
  50. package/src/cli/koi.js +793 -0
  51. package/src/compiler/build-optimizer.js +447 -0
  52. package/src/compiler/cache-manager.js +274 -0
  53. package/src/compiler/import-resolver.js +369 -0
  54. package/src/compiler/parser.js +7542 -0
  55. package/src/compiler/transpiler.js +1105 -0
  56. package/src/compiler/typescript-transpiler.js +148 -0
  57. package/src/grammar/koi.pegjs +767 -0
  58. package/src/runtime/action-registry.js +172 -0
  59. package/src/runtime/actions/call-skill.js +45 -0
  60. package/src/runtime/actions/format.js +115 -0
  61. package/src/runtime/actions/print.js +42 -0
  62. package/src/runtime/actions/registry-delete.js +37 -0
  63. package/src/runtime/actions/registry-get.js +37 -0
  64. package/src/runtime/actions/registry-keys.js +33 -0
  65. package/src/runtime/actions/registry-search.js +34 -0
  66. package/src/runtime/actions/registry-set.js +50 -0
  67. package/src/runtime/actions/return.js +31 -0
  68. package/src/runtime/actions/send-message.js +58 -0
  69. package/src/runtime/actions/update-state.js +36 -0
  70. package/src/runtime/agent.js +1368 -0
  71. package/src/runtime/cli-logger.js +205 -0
  72. package/src/runtime/incremental-json-parser.js +201 -0
  73. package/src/runtime/index.js +33 -0
  74. package/src/runtime/llm-provider.js +1372 -0
  75. package/src/runtime/mcp-client.js +1171 -0
  76. package/src/runtime/planner.js +273 -0
  77. package/src/runtime/registry-backends/keyv-sqlite.js +215 -0
  78. package/src/runtime/registry-backends/local.js +260 -0
  79. package/src/runtime/registry.js +162 -0
  80. package/src/runtime/role.js +14 -0
  81. package/src/runtime/router.js +395 -0
  82. package/src/runtime/runtime.js +113 -0
  83. package/src/runtime/skill-selector.js +173 -0
  84. package/src/runtime/skill.js +25 -0
  85. package/src/runtime/team.js +162 -0
@@ -0,0 +1,184 @@
1
+ // Registry Demo - Shared data store between agents
2
+ package "registry.demo"
3
+
4
+ role Worker { can execute }
5
+
6
+ // Agent that writes data to the registry
7
+ Agent Writer : Worker {
8
+ on saveUser(args: Json) {
9
+ const userId = args.id
10
+ const userData = {
11
+ name: args.name,
12
+ age: args.age,
13
+ email: args.email,
14
+ createdAt: Date.now()
15
+ }
16
+
17
+ await registry.set("user:" + userId, userData)
18
+
19
+ console.log("✅ Saved user:", userId)
20
+ return { saved: true, userId: userId }
21
+ }
22
+
23
+ on saveConfig(args: Json) {
24
+ await registry.set("config:app", {
25
+ theme: args.theme || "dark",
26
+ language: args.language || "en",
27
+ notifications: args.notifications !== false
28
+ })
29
+
30
+ console.log("✅ Saved config")
31
+ return { saved: true }
32
+ }
33
+ }
34
+
35
+ // Agent that reads data from the registry
36
+ Agent Reader : Worker {
37
+ on getUser(args: Json) {
38
+ const userId = args.id
39
+ const user = await registry.get("user:" + userId)
40
+
41
+ if (!user) {
42
+ console.log("❌ User not found:", userId)
43
+ return { found: false, userId: userId }
44
+ }
45
+
46
+ console.log("📖 Retrieved user:", user.name)
47
+ return { found: true, user: user }
48
+ }
49
+
50
+ on getConfig(args: Json) {
51
+ const config = await registry.get("config:app")
52
+
53
+ if (!config) {
54
+ console.log("⚙️ No config found, using defaults")
55
+ return { found: false, config: null }
56
+ }
57
+
58
+ console.log("⚙️ Retrieved config:", JSON.stringify(config))
59
+ return { found: true, config: config }
60
+ }
61
+
62
+ on listUsers(args: Json) {
63
+ const userKeys = await registry.keys("user:")
64
+ console.log("📋 Found", userKeys.length, "users")
65
+
66
+ const users = []
67
+ for (const key of userKeys) {
68
+ const user = await registry.get(key)
69
+ users.push({ id: key.replace("user:", ""), ...user })
70
+ }
71
+
72
+ return { count: users.length, users: users }
73
+ }
74
+ }
75
+
76
+ // Agent that searches the registry
77
+ Agent Searcher : Worker {
78
+ on findAdults(args: Json) {
79
+ const results = await registry.search({
80
+ age: { $gte: 18 }
81
+ })
82
+
83
+ console.log("🔍 Found", results.length, "adults")
84
+
85
+ const adults = results.map(r => ({
86
+ id: r.key.replace("user:", ""),
87
+ ...r.value
88
+ }))
89
+
90
+ return { count: adults.length, adults: adults }
91
+ }
92
+
93
+ on findByName(args: Json) {
94
+ const results = await registry.search({
95
+ name: { $regex: args.pattern }
96
+ })
97
+
98
+ console.log("🔍 Found", results.length, "matching users")
99
+
100
+ const matches = results.map(r => ({
101
+ id: r.key.replace("user:", ""),
102
+ ...r.value
103
+ }))
104
+
105
+ return { count: matches.length, matches: matches }
106
+ }
107
+ }
108
+
109
+ // Orchestrator that coordinates the demo
110
+ Agent Demo : Worker {
111
+ on start(args: Json) {
112
+ console.log("═════════════════════════════════════════════")
113
+ console.log(" Registry Demo - Shared Data Store")
114
+ console.log("═════════════════════════════════════════════")
115
+ console.log("")
116
+
117
+ // 1. Save some users
118
+ console.log("1️⃣ Saving users...")
119
+ await Writer.handle("saveUser", { id: "001", name: "Alice", age: 30, email: "alice@example.com" })
120
+ await Writer.handle("saveUser", { id: "002", name: "Bob", age: 25, email: "bob@example.com" })
121
+ await Writer.handle("saveUser", { id: "003", name: "Charlie", age: 17, email: "charlie@example.com" })
122
+ await Writer.handle("saveUser", { id: "004", name: "Diana", age: 35, email: "diana@example.com" })
123
+ console.log("")
124
+
125
+ // 2. Save config
126
+ console.log("2️⃣ Saving config...")
127
+ await Writer.handle("saveConfig", { theme: "light", language: "es", notifications: true })
128
+ console.log("")
129
+
130
+ // 3. Read individual user
131
+ console.log("3️⃣ Reading user...")
132
+ const userResult = await Reader.handle("getUser", { id: "001" })
133
+ console.log(" User:", JSON.stringify(userResult.user, null, 2))
134
+ console.log("")
135
+
136
+ // 4. Read config
137
+ console.log("4️⃣ Reading config...")
138
+ const configResult = await Reader.handle("getConfig", {})
139
+ console.log(" Config:", JSON.stringify(configResult.config, null, 2))
140
+ console.log("")
141
+
142
+ // 5. List all users
143
+ console.log("5️⃣ Listing all users...")
144
+ const listResult = await Reader.handle("listUsers", {})
145
+ for (const user of listResult.users) {
146
+ console.log(" -", user.name, "(" + user.age + " years old)")
147
+ }
148
+ console.log("")
149
+
150
+ // 6. Search for adults
151
+ console.log("6️⃣ Searching for adults (age >= 18)...")
152
+ const adultsResult = await Searcher.handle("findAdults", {})
153
+ for (const adult of adultsResult.adults) {
154
+ console.log(" -", adult.name, "(" + adult.age + " years old)")
155
+ }
156
+ console.log("")
157
+
158
+ // 7. Search by name pattern
159
+ console.log("7️⃣ Searching for names containing 'a'...")
160
+ const searchResult = await Searcher.handle("findByName", { pattern: "a" })
161
+ for (const match of searchResult.matches) {
162
+ console.log(" -", match.name)
163
+ }
164
+ console.log("")
165
+
166
+ // 8. Show stats
167
+ console.log("8️⃣ Registry stats...")
168
+ const stats = await registry.stats()
169
+ console.log(" Backend:", stats.backend)
170
+ console.log(" Entries:", stats.count)
171
+ console.log(" File:", stats.file)
172
+ console.log(" Size:", stats.size, "bytes")
173
+ console.log("")
174
+
175
+ console.log("═════════════════════════════════════════════")
176
+ console.log(" Demo Complete!")
177
+ console.log(" Data persisted to:", stats.file)
178
+ console.log("═════════════════════════════════════════════")
179
+
180
+ return { success: true }
181
+ }
182
+ }
183
+
184
+ run Demo.start({})
@@ -0,0 +1,162 @@
1
+ // Registry with Natural Language Playbooks Demo
2
+ // Shows how agents can use registry operations naturally in playbooks
3
+ package "registry.playbook.demo"
4
+
5
+ role Worker { can execute, can registry }
6
+ role Manager { can execute, can delegate }
7
+
8
+ // Agent that uses natural language to interact with registry
9
+ Agent UserManager : Worker {
10
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
11
+
12
+ on createAllUser(args: Json) {
13
+ playbook """
14
+ Create all given users via args, with the following attributes
15
+ - name, age, email
16
+
17
+ Save all to registry with key "user:id being id an unique identifier".
18
+ Include all fields plus a createdAt timestamp.
19
+ Return: { "success": true, "message": "Users created" }
20
+
21
+ DO NOT add print actions - just return the data.
22
+ """
23
+ }
24
+
25
+ on createUser(args: Json) {
26
+ playbook """
27
+ Create a new user with:
28
+ - name: ${args.name}
29
+ - age: ${args.age}
30
+ - email: ${args.email}
31
+
32
+ Save to registry with key "user:${args.id}".
33
+ Include all fields plus a createdAt timestamp.
34
+ Return: { "success": true, "message": "User created" }
35
+
36
+ DO NOT add print actions - just return the data.
37
+ """
38
+ }
39
+
40
+ on getUser(args: Json) {
41
+ playbook """
42
+ Get user ${args.id} from registry.
43
+
44
+ Use registry_get with key "user:${args.id}".
45
+ Extract the .value field from the registry_get result (which contains the user data).
46
+ Return ONLY the user data object (name, age, email, createdAt) without any wrapper.
47
+ """
48
+ }
49
+
50
+ on listAllUsers(args: Json) {
51
+ playbook """
52
+ List all users in the registry.
53
+
54
+ EXACT STEPS:
55
+ 1. Use registry_search with an empty query {} to get ALL users, store with ID "a1"
56
+ 2. Extract just the user data (the .value field) from each result
57
+ 3. Return: { "count": <count from a1>, "users": <array of user value objects, NOT the full {key, value} wrappers> }
58
+
59
+ Example: If a1.output.results = [{key: "user:001", value: {name: "Alice", age: 30}}, ...]
60
+ Then return: { "count": 2, "users": [{name: "Alice", age: 30}, ...] }
61
+
62
+ CRITICAL: Extract ONLY the .value objects so caller can access with .users[0].name directly
63
+ DO NOT use format action - return a real array!
64
+ """
65
+ }
66
+
67
+ on findAdults(args: Json) {
68
+ playbook """
69
+ Find all users aged 18 or older using registry search with query: { "age": { "$gte": 18 } }
70
+
71
+ EXACT STEPS:
72
+ 1. Use registry_search with query: { "age": { "$gte": 18 } }
73
+ 2. Return: { "count": [count from search], "adults": [results array] }
74
+
75
+ DO NOT add print actions - just return the data!
76
+ """
77
+ }
78
+
79
+ on updateUserAge(args: Json) {
80
+ playbook """
81
+ Update user ${args.id}'s age to ${args.age}.
82
+
83
+ EXACT STEPS:
84
+ 1. Use registry_get with key "user:${args.id}", store with ID "a1"
85
+ 2. Take the full user object from \${a1.output.value}
86
+ 3. Modify ONLY the age field to ${args.age}, keep all other fields (name, email, createdAt, etc.)
87
+ 4. Use registry_set with key "user:${args.id}" and the complete updated object
88
+ 5. Return: { "success": true, "message": "Age updated" }
89
+
90
+ CRITICAL: Preserve ALL existing fields when saving!
91
+ """
92
+ }
93
+
94
+ on deleteUser(args: Json) {
95
+ playbook """
96
+ Borra el usuario del registro con ID ${args.id}.
97
+
98
+ EXACT STEPS:
99
+ 1. Use registry_delete with key "user:\${args.id}"
100
+ 2. Return: { "success": true, "message": "User deleted" }
101
+ """
102
+ }
103
+ }
104
+
105
+ // Team that groups our agents
106
+ Team RegistryTeam {
107
+ userManager = UserManager
108
+ }
109
+
110
+ // Orchestrator - uses playbook, router finds UserManager automatically!
111
+ Agent Demo : Manager {
112
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
113
+ uses Team RegistryTeam
114
+
115
+ on start(args: Json) {
116
+ //SUPER IMPORTANT: DO NOT CHANGE THE FOLLOWING PROMPT AT ALL!!!!!!
117
+ playbook """
118
+ Ejecuta un demo del registro de usuarios.
119
+
120
+ Muestra el header:
121
+ ╔══════════════════════════════════════════════════╗
122
+ ║ Registry with Playbook Demo ║
123
+ ╚══════════════════════════════════════════════════╝
124
+
125
+ 1️⃣ Crea estos usuarios:
126
+ - Alice: id=001, age=30, email=alice@example.com
127
+ - Bob: id=002, de 17 años, bob@example.com
128
+ - Charlie: id=003, age=25, email=charlie@example.com
129
+ - Diana: id=004, age is 35, diana@example.com
130
+ - Erika: id=005, age=28, email=erika@example.com
131
+ - Fernando: id=006, age=32, fernando@example.com
132
+ Muestra: " ✅ X users created" X es la cantidad de usuarios que se crearon
133
+
134
+ 2️⃣ Obtén el usuario 001
135
+ Muestra: " ✅ Found user: {el nombre del usuario}, age {su edad}"
136
+
137
+ 3️⃣ Lista todos los usuarios
138
+ Muestra: " ✅ Found {la cantidad de usuarios} users y luego por cada uno muestra en una tabla en markdown: sr o sra si es chico o chica (esto deducelo por el nombre) y luego {el nombre del usuario}, age {su edad}"
139
+
140
+ 4️⃣ Busca usuarios mayores de 18 años
141
+ Muestra: " ✅ Found {la cantidad encontrada} adults"
142
+
143
+ 5️⃣ Actualiza la edad de Bob (002) a 19 años
144
+ Luego obtén el usuario actualizado
145
+ Muestra: " ✅ Bob is now {su nueva edad} years old"
146
+
147
+ 6️⃣ Elimina a Charlie (003)
148
+ Luego lista los usuarios restantes
149
+ Muestra: " ✅ Remaining users: {la cantidad restante}"
150
+
151
+ 7️⃣ Vuelve a listar todos los usuarios como lo has hecho en el paso 3️⃣
152
+ Muestra los usuarios que hay en la tabla en markdown con el mismo formato que en el paso 3️⃣
153
+
154
+ Muestra el footer:
155
+ ╔══════════════════════════════════════════════════╗
156
+ ║ Demo completed successfully! ║
157
+ ╚══════════════════════════════════════════════════╝
158
+ """
159
+ }
160
+ }
161
+
162
+ run Demo.start({})
@@ -0,0 +1,140 @@
1
+ // Registry with Natural Language Playbooks Demo
2
+ // Shows how agents can use registry operations naturally in playbooks
3
+ package "registry.playbook.demo"
4
+
5
+ role Worker { can execute, can registry }
6
+ role Manager { can execute, can delegate }
7
+
8
+ // Agent that uses natural language to interact with registry
9
+ Agent UserManager : Worker {
10
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
11
+
12
+ on createUser(args: Json) {
13
+ playbook """
14
+ Create a new user with ALL fields from args:
15
+ - name: ${args.name}
16
+ - age: ${args.age}
17
+ - email: ${args.email}
18
+ - birthdate: ${args.birthdate} (if provided)
19
+ - id: ${args.id}
20
+
21
+ Save to registry with key "user:${args.id}".
22
+ CRITICAL: Include ALL fields from args (name, age, email, birthdate, id) plus a createdAt timestamp.
23
+ Return: { "success": true, "message": "User created" }
24
+
25
+ DO NOT add print actions - just return the data.
26
+ """
27
+ }
28
+
29
+ on getUser(args: Json) {
30
+ playbook """
31
+ Get user ${args.id} from registry.
32
+
33
+ Use registry_get with key "user:${args.id}".
34
+ Extract the .value field from the registry_get result (which contains the user data).
35
+ Return ONLY the user data object (name, age, email, createdAt) without any wrapper.
36
+ """
37
+ }
38
+
39
+ on listAllUsers(args: Json) {
40
+ playbook """
41
+ List all users in the registry.
42
+
43
+ EXACT STEPS:
44
+ 1. Use registry_search with an empty query {} to get ALL users, store with ID "a1"
45
+ 2. Extract just the user data (the .value field) from each result
46
+ 3. Return: { "count": <count from a1>, "users": <array of user value objects, NOT the full {key, value} wrappers> }
47
+
48
+ Example: If a1.output.results = [{key: "user:001", value: {name: "Alice", age: 30}}, ...]
49
+ Then return: { "count": 2, "users": [{name: "Alice", age: 30}, ...] }
50
+
51
+ CRITICAL: Extract ONLY the .value objects so caller can access with .users[0].name directly
52
+ DO NOT use format action - return a real array!
53
+ """
54
+ }
55
+
56
+ on findAdults(args: Json) {
57
+ playbook """
58
+ Find all users aged 18 or older using registry search with query: { "age": { "$gte": 18 } }
59
+
60
+ EXACT STEPS:
61
+ 1. Use registry_search with query: { "age": { "$gte": 18 } }
62
+ 2. Return: { "count": [count from search], "adults": [results array] }
63
+
64
+ DO NOT add print actions - just return the data!
65
+ """
66
+ }
67
+
68
+ on updateUserAge(args: Json) {
69
+ playbook """
70
+ Update user ${args.id}'s age to ${args.age}.
71
+
72
+ EXACT STEPS:
73
+ 1. Use registry_get with key "user:${args.id}", store with ID "a1"
74
+ 2. Take the full user object from \${a1.output.value}
75
+ 3. Modify ONLY the age field to ${args.age}, keep all other fields (name, email, createdAt, etc.)
76
+ 4. Use registry_set with key "user:${args.id}" and the complete updated object
77
+ 5. Return: { "success": true, "message": "Age updated" }
78
+
79
+ CRITICAL: Preserve ALL existing fields when saving!
80
+ """
81
+ }
82
+
83
+ on deleteUser(args: Json) {
84
+ playbook """
85
+ Borra el usuario del registro con ID ${args.id}.
86
+
87
+ EXACT STEPS:
88
+ 1. Use registry_delete with key "user:\${args.id}"
89
+ 2. Return: { "success": true, "message": "User deleted" }
90
+ """
91
+ }
92
+ }
93
+
94
+ // Team that groups our agents
95
+ Team RegistryTeam {
96
+ userManager = UserManager
97
+ }
98
+
99
+ // Orchestrator - uses playbook, router finds UserManager automatically!
100
+ Agent Demo : Manager {
101
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
102
+ uses Team RegistryTeam
103
+
104
+ on start(args: Json) {
105
+ //SUPER IMPORTANT: DO NOT CHANGE THE FOLLOWING PROMPT AT ALL!!!!!!
106
+ playbook """
107
+ Ejecuta un demo del registro de usuarios.
108
+
109
+ Muestra el header:
110
+ ╔══════════════════════════════════════════════════╗
111
+ ║ Registry with Playbook Demo ║
112
+ ╚══════════════════════════════════════════════════╝
113
+
114
+ 1️⃣ Crea estos usuarios:
115
+ - Alice: id=001, birthdate=1985-12-05, email=alice@example.com
116
+ - Bob: id=002, fecha de nacimiento: 12 de abril de 2001, bob@example.com
117
+ - Moema: id=003, birth date: 1992 enero 29, email=charlie@example.com
118
+ - Diana: id=004, birthdate: 12 del 12 del 12, diana@example.com
119
+ Muestra: " ✅ X users created" X es la cantidad de usuarios que se crearon
120
+
121
+ 2️⃣ Por cada usuario en la base de datos, escribe este correo:
122
+
123
+ Estimado (o Estimada si es chica, deducelo por el nombre) <nombre persona>,
124
+
125
+ Como sabemos que usted tiene {x} años, le queremos dar la enhorabuena!
126
+
127
+ Atentamente,
128
+ La empresa!!
129
+
130
+ Muestra cada correo que escribieste.
131
+
132
+ Muestra el footer:
133
+ ╔══════════════════════════════════════════════════╗
134
+ ║ Demo completed successfully! ║
135
+ ╚══════════════════════════════════════════════════╝
136
+ """
137
+ }
138
+ }
139
+
140
+ run Demo.start({})
@@ -0,0 +1,140 @@
1
+ // Registry with Natural Language Playbooks Demo
2
+ // Shows how agents can use registry operations naturally in playbooks
3
+ package "registry.playbook.demo"
4
+
5
+ role Worker { can execute, can registry }
6
+ role Manager { can execute, can delegate }
7
+
8
+ // Agent that uses natural language to interact with registry
9
+ Agent UserManager : Worker {
10
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
11
+
12
+ on createUser(args: Json) {
13
+ playbook """
14
+ Create a new user with:
15
+ - name: ${args.name}
16
+ - age: ${args.age}
17
+ - email: ${args.email}
18
+
19
+ Save to registry with key "user:${args.id}".
20
+ Include all fields plus a createdAt timestamp.
21
+ Return: { "success": true, "message": "User created" }
22
+
23
+ DO NOT add print actions - just return the data.
24
+ """
25
+ }
26
+
27
+ on getUser(args: Json) {
28
+ playbook """
29
+ Get user ${args.id} from registry.
30
+
31
+ Use registry_get with key "user:${args.id}".
32
+ Extract the .value field from the registry_get result (which contains the user data).
33
+ Return ONLY the user data object (name, age, email, createdAt) without any wrapper.
34
+ """
35
+ }
36
+
37
+ on listAllUsers(args: Json) {
38
+ playbook """
39
+ List all users in the registry.
40
+
41
+ EXACT STEPS:
42
+ 1. Use registry_search with an empty query {} to get ALL users, store with ID "a1"
43
+ 2. Extract just the user data (the .value field) from each result
44
+ 3. Return: { "count": <count from a1>, "users": <array of user value objects, NOT the full {key, value} wrappers> }
45
+
46
+ Example: If a1.output.results = [{key: "user:001", value: {name: "Alice", age: 30}}, ...]
47
+ Then return: { "count": 2, "users": [{name: "Alice", age: 30}, ...] }
48
+
49
+ CRITICAL: Extract ONLY the .value objects so caller can access with .users[0].name directly
50
+ DO NOT use format action - return a real array!
51
+ """
52
+ }
53
+
54
+ on findAdults(args: Json) {
55
+ playbook """
56
+ Find all users aged 18 or older using registry search with query: { "age": { "$gte": 18 } }
57
+
58
+ EXACT STEPS:
59
+ 1. Use registry_search with query: { "age": { "$gte": 18 } }
60
+ 2. Return: { "count": [count from search], "adults": [results array] }
61
+
62
+ DO NOT add print actions - just return the data!
63
+ """
64
+ }
65
+
66
+ on updateUserAge(args: Json) {
67
+ playbook """
68
+ Update user ${args.id}'s age to ${args.age}.
69
+
70
+ EXACT STEPS:
71
+ 1. Use registry_get with key "user:${args.id}", store with ID "a1"
72
+ 2. Take the full user object from \${a1.output.value}
73
+ 3. Modify ONLY the age field to ${args.age}, keep all other fields (name, email, createdAt, etc.)
74
+ 4. Use registry_set with key "user:${args.id}" and the complete updated object
75
+ 5. Return: { "success": true, "message": "Age updated" }
76
+
77
+ CRITICAL: Preserve ALL existing fields when saving!
78
+ """
79
+ }
80
+
81
+ on deleteUser(args: Json) {
82
+ playbook """
83
+ Borra el usuario del registro con ID ${args.id}.
84
+
85
+ EXACT STEPS:
86
+ 1. Use registry_delete with key "user:\${args.id}"
87
+ 2. Return: { "success": true, "message": "User deleted" }
88
+ """
89
+ }
90
+ }
91
+
92
+ // Team that groups our agents
93
+ Team RegistryTeam {
94
+ userManager = UserManager
95
+ }
96
+
97
+ // Orchestrator - uses playbook, router finds UserManager automatically!
98
+ Agent Demo : Manager {
99
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
100
+ uses Team RegistryTeam
101
+
102
+ on start(args: Json) {
103
+ //SUPER IMPORTANT: DO NOT CHANGE THE FOLLOWING PROMPT AT ALL!!!!!!
104
+ playbook """
105
+ Ejecuta un demo del registro de usuarios.
106
+
107
+ Muestra el header:
108
+ ╔══════════════════════════════════════════════════╗
109
+ ║ Registry with Playbook Demo ║
110
+ ╚══════════════════════════════════════════════════╝
111
+
112
+ 1️⃣ Crea estos usuarios:
113
+ - Alice: id=001, age=30, email=alice@example.com
114
+ - Bob: id=002, de 17 años, bob@example.com
115
+ - Charlie: id=003, age=25, email=charlie@example.com
116
+ - Diana: id=004, age is 35, diana@example.com
117
+ - Erika: id=005, age=28, email=erika@example.com
118
+ - Fernando: id=006, age=32, fernando@example.com
119
+ Muestra: " ✅ X users created" X es la cantidad de usuarios que se crearon
120
+
121
+ 2️⃣ Por cada usuario en la base de datos, escribe este correo:
122
+
123
+ Estimado (o Estimada si es chica, deducelo por el nombre),
124
+
125
+ Como sabemos que usted tiene {x} años, le queremos dar la enhorabuena!
126
+
127
+ Atentamente,
128
+ La empresa!!
129
+
130
+ Muestra cada correo que escribieste.
131
+
132
+ Muestra el footer:
133
+ ╔══════════════════════════════════════════════════╗
134
+ ║ Demo completed successfully! ║
135
+ ╚══════════════════════════════════════════════════╝
136
+ """
137
+ }
138
+ }
139
+
140
+ run Demo.start({})