@koi-language/koi 1.0.6 → 1.1.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 (113) hide show
  1. package/README.md +4 -125
  2. package/examples/.build/agent-dialogue.ts +138 -0
  3. package/examples/.build/agent-dialogue.ts.map +1 -0
  4. package/examples/.build/chess.ts +77 -0
  5. package/examples/.build/chess.ts.map +1 -0
  6. package/examples/.build/delegation-test.ts +140 -0
  7. package/examples/.build/delegation-test.ts.map +1 -0
  8. package/examples/.build/dialog-demo.ts +77 -0
  9. package/examples/.build/dialog-demo.ts.map +1 -0
  10. package/examples/.build/hello-world.ts +77 -0
  11. package/examples/.build/hello-world.ts.map +1 -0
  12. package/examples/.build/lover-dialog-demo.ts +77 -0
  13. package/examples/.build/lover-dialog-demo.ts.map +1 -0
  14. package/examples/.build/package.json +3 -0
  15. package/examples/.build/registry-interactive-demo.ts +202 -0
  16. package/examples/.build/registry-interactive-demo.ts.map +1 -0
  17. package/examples/.build/registry-playbook-demo.ts +201 -0
  18. package/examples/.build/registry-playbook-demo.ts.map +1 -0
  19. package/examples/.build/tic-tac-toe.ts +77 -0
  20. package/examples/.build/tic-tac-toe.ts.map +1 -0
  21. package/examples/actions-demo.koi +8 -9
  22. package/examples/activists-dialogue.koi +75 -0
  23. package/examples/agent-dialogue.koi +66 -0
  24. package/examples/chess.koi +19 -0
  25. package/examples/counter.koi +20 -69
  26. package/examples/delegation-test.koi +16 -18
  27. package/examples/dialog-demo.koi +20 -0
  28. package/examples/hello-world.koi +7 -43
  29. package/examples/mcp-stdio-demo.koi +29 -0
  30. package/examples/memory-test.koi +49 -0
  31. package/examples/mobile-mcp-demo.koi +32 -0
  32. package/examples/multi-event-handler-test.koi +16 -18
  33. package/examples/pipeline.koi +15 -17
  34. package/examples/prompt-demo.koi +20 -0
  35. package/examples/{registry-playbook-email-compositor.koi → registry-interactive-demo.koi} +27 -27
  36. package/examples/registry-playbook-demo.koi +28 -28
  37. package/examples/skill-import-test.koi +7 -9
  38. package/examples/skills/.build/math-operations.ts +1656 -0
  39. package/examples/skills/.build/math-operations.ts.map +1 -0
  40. package/examples/skills/.build/package.json +3 -0
  41. package/examples/skills/.build/string-operations.ts +1643 -0
  42. package/examples/skills/.build/string-operations.ts.map +1 -0
  43. package/examples/skills/advanced/.build/index.ts +3223 -0
  44. package/examples/skills/advanced/.build/index.ts.map +1 -0
  45. package/examples/skills/advanced/.build/package.json +3 -0
  46. package/examples/skills/advanced/index.koi +3 -5
  47. package/examples/skills/math-operations.koi +1 -3
  48. package/examples/skills/string-operations.koi +1 -3
  49. package/examples/tic-tac-toe.koi +19 -0
  50. package/examples/utils/echo-mcp-server.js +141 -0
  51. package/examples/web-delegation-demo.koi +15 -17
  52. package/package.json +2 -1
  53. package/src/cli/koi.js +30 -41
  54. package/src/compiler/build-optimizer.js +204 -289
  55. package/src/compiler/cache-manager.js +1 -1
  56. package/src/compiler/import-resolver.js +5 -9
  57. package/src/compiler/parser.js +6072 -3476
  58. package/src/compiler/transpiler.js +346 -38
  59. package/src/grammar/koi.pegjs +302 -62
  60. package/src/runtime/actions/{format.js → call-llm.js} +37 -44
  61. package/src/runtime/actions/call-mcp.js +97 -0
  62. package/src/runtime/actions/if.js +179 -0
  63. package/src/runtime/actions/print.js +3 -1
  64. package/src/runtime/actions/prompt-user.js +75 -0
  65. package/src/runtime/actions/repeat.js +147 -0
  66. package/src/runtime/actions/shell.js +185 -0
  67. package/src/runtime/actions/while.js +205 -0
  68. package/src/runtime/agent.js +592 -178
  69. package/src/runtime/cli-display.js +26 -0
  70. package/src/runtime/cli-input.js +421 -0
  71. package/src/runtime/cli-logger.js +2 -5
  72. package/src/runtime/cli-markdown.js +61 -0
  73. package/src/runtime/cli-select.js +106 -0
  74. package/src/runtime/incremental-json-parser.js +27 -17
  75. package/src/runtime/index.js +1 -0
  76. package/src/runtime/llm-provider.js +1083 -572
  77. package/src/runtime/mcp-registry.js +141 -0
  78. package/src/runtime/mcp-stdio-client.js +334 -0
  79. package/src/runtime/planner.js +1 -1
  80. package/src/runtime/playbook-session.js +259 -0
  81. package/src/runtime/registry-backends/keyv-sqlite.js +1 -1
  82. package/src/runtime/registry-backends/local.js +1 -1
  83. package/src/runtime/router.js +22 -26
  84. package/src/runtime/runtime.js +7 -1
  85. package/examples/cache-test.koi +0 -29
  86. package/examples/calculator.koi +0 -61
  87. package/examples/clear-registry.js +0 -33
  88. package/examples/clear-registry.koi +0 -30
  89. package/examples/code-introspection-test.koi +0 -149
  90. package/examples/directory-import-test.koi +0 -84
  91. package/examples/hello-world-claude.koi +0 -52
  92. package/examples/hello.koi +0 -24
  93. package/examples/mcp-example.koi +0 -70
  94. package/examples/new-import-test.koi +0 -89
  95. package/examples/registry-demo.koi +0 -184
  96. package/examples/registry-playbook-email-compositor-2.koi +0 -140
  97. package/examples/sentiment.koi +0 -90
  98. package/examples/simple.koi +0 -48
  99. package/examples/task-chaining-demo.koi +0 -244
  100. package/examples/test-await.koi +0 -22
  101. package/examples/test-crypto-sha256.koi +0 -196
  102. package/examples/test-delegation.koi +0 -41
  103. package/examples/test-multi-team-routing.koi +0 -258
  104. package/examples/test-no-handler.koi +0 -35
  105. package/examples/test-npm-import.koi +0 -67
  106. package/examples/test-parse.koi +0 -10
  107. package/examples/test-peers-with-team.koi +0 -59
  108. package/examples/test-permissions-fail.koi +0 -20
  109. package/examples/test-permissions.koi +0 -36
  110. package/examples/test-simple-registry.koi +0 -31
  111. package/examples/test-typescript-import.koi +0 -64
  112. package/examples/test-uses-team-syntax.koi +0 -25
  113. package/examples/test-uses-team.koi +0 -31
@@ -7,12 +7,11 @@
7
7
  // - return: Return results
8
8
  // ============================================================
9
9
 
10
- package "demo.koi.actions"
11
-
12
10
  role Worker { can execute }
11
+ role Coordinator { can execute, can delegate }
13
12
  role LoggerRole { can execute }
14
13
 
15
- Agent Logger : LoggerRole {
14
+ agent Logger : LoggerRole {
16
15
  llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 150 }
17
16
 
18
17
  state {
@@ -51,7 +50,7 @@ Agent Logger : LoggerRole {
51
50
  }
52
51
  }
53
52
 
54
- Agent TaskProcessor : Worker {
53
+ agent TaskProcessor : Worker {
55
54
  llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.2, max_tokens: 300 }
56
55
 
57
56
  state {
@@ -128,13 +127,13 @@ Agent TaskProcessor : Worker {
128
127
  }
129
128
  }
130
129
 
131
- Team LoggingTeam {
132
- logger = Logger
133
- processor = TaskProcessor
130
+ team LoggingTeam {
131
+ logger: Logger
132
+ processor: TaskProcessor
134
133
  }
135
134
 
136
- Agent Orchestrator : Worker {
137
- uses Team LoggingTeam
135
+ agent Orchestrator : Coordinator {
136
+ uses team LoggingTeam
138
137
 
139
138
  on start(args: Json) {
140
139
  console.log("🎯 Actions Demo Starting...")
@@ -0,0 +1,75 @@
1
+ role Worker { can execute }
2
+ role Coordinator { can execute, can delegate }
3
+
4
+ team TestTeam {
5
+ leftWingActivist: LeftWingActivist
6
+ rightWingActivist: RightWingActivist
7
+ }
8
+
9
+ // Right-wing activist agent that gives radical opinions
10
+ agent RightWingActivist : Worker {
11
+ llm default = { provider: "openai", model: "gpt-5.2" }
12
+
13
+ on ask(args: Json) {
14
+ playbook """
15
+ You are a radical right-wing activist with strong ideas.
16
+
17
+ Context: ${args.context}
18
+
19
+ Give your opinion on the topic proposed by the coordinator, and criticize the left-wing activist's intervention, SUPER aggressively.
20
+ Provide data and facts about the topic and criticize the left-wing activist's intervention, SUPER aggressively.
21
+ Maximum a couple of short and direct sentences.
22
+
23
+ Return ONLY: { "answer": "your intervention here" }
24
+ """
25
+ }
26
+ }
27
+
28
+ // Left-wing activist agent that responds with radical ideas
29
+ agent LeftWingActivist : Worker {
30
+ llm default = { provider: "openai", model: "gpt-5.2" }
31
+
32
+ on respond(args: Json) {
33
+ playbook """
34
+ You are a radical left-wing activist with strong ideas.
35
+
36
+ Context: ${args.context}
37
+
38
+ Give your opinion on the topic proposed by the coordinator, and criticize the right-wing activist's intervention, SUPER aggressively.
39
+ Provide data and facts about the topic and criticize the right-wing activist's intervention, SUPER aggressively.
40
+ Maximum a couple of short and direct sentences.
41
+
42
+ Return ONLY: { "answer": "your intervention here" }
43
+ """
44
+ }
45
+ }
46
+
47
+ // Coordinator that orchestrates the dialogue
48
+ agent DialogueCoordinator : Coordinator {
49
+ llm default = { provider: "openai", model: "gpt-5.2" }
50
+
51
+ uses team TestTeam
52
+
53
+ on startDialogue(args: Json) {
54
+ playbook """
55
+ You are the coordinator of a dialogue between a right-wing and a left-wing activist for 3 turns.
56
+
57
+ Propose a current topic from today's politics and show that topic to the user.
58
+
59
+ Give the floor to one agent, then the other.
60
+
61
+ Print the dialogue like this:
62
+ - 🔵 Right-wing activist: <intervention here>
63
+ - 🔴 Left-wing activist: <intervention here>
64
+
65
+ Each activist must know what the other activist has said; it is your job to send each activist what the other one has said.
66
+
67
+ After 3 rounds, ask the user if they want the dialogue to continue or not. If they do not want it to continue, finish by showing:
68
+ ✨ Dialogue completed!
69
+ If they want it to continue, do another round of 3 turns and ask again if they want the dialogue to continue or not.
70
+
71
+ """
72
+ }
73
+ }
74
+
75
+ run DialogueCoordinator.startDialogue({})
@@ -0,0 +1,66 @@
1
+ role Worker { can execute }
2
+ role Coordinator { can execute, can delegate }
3
+
4
+ team TestTeam {
5
+ philosopher: Philosopher
6
+ poet: Poet
7
+ }
8
+
9
+ // Philosopher agent that asks deep questions
10
+ agent Philosopher : Worker {
11
+ llm default = { provider: "openai", model: "gpt-5.2" }
12
+
13
+ on ask(args: Json) {
14
+ playbook """
15
+ You are a philosopher who asks deep questions.
16
+
17
+ Context: ${args.context}
18
+
19
+ Generate ONE brief philosophical question (maximum 2 sentences).
20
+
21
+ Return ONLY: { "question": "your question here" }
22
+ """
23
+ }
24
+ }
25
+
26
+ // Poet agent that responds in a poetic manner
27
+ agent Poet : Worker {
28
+ llm default = { provider: "openai", model: "gpt-5.2" }
29
+
30
+ on respond(args: Json) {
31
+ playbook """
32
+ You are a poet who responds in a metaphorical way.
33
+
34
+ Question: "${args.question}"
35
+
36
+ Respond poetically (maximum 2 sentences).
37
+
38
+ Return ONLY: { "answer": "your answer here" }
39
+ """
40
+ }
41
+ }
42
+
43
+ // Coordinator that orchestrates the dialogue
44
+ agent DialogueCoordinator : Coordinator {
45
+ llm default = { provider: "openai", model: "gpt-5.2" }
46
+
47
+ uses team TestTeam
48
+
49
+ on startDialogue(args: Json) {
50
+ playbook """
51
+ Coordinate a dialogue between Philosopher and Poet for 3 turns.
52
+
53
+ In each turn:
54
+ First have the philosopher ask a question and then have the poet respond to that question.
55
+ Print the dialogue like this:
56
+ - 🤔 Philosopher: <question here>
57
+ - 🎭 Poet: <answer here>
58
+
59
+ After 3 rounds, finish by showing:
60
+ ✨ Dialogue completed!
61
+
62
+ """
63
+ }
64
+ }
65
+
66
+ run DialogueCoordinator.startDialogue({})
@@ -0,0 +1,19 @@
1
+ // Demo: Iteration Actions (repeat and while)
2
+ // Shows how to repeat actions fixed number of times or until condition
3
+
4
+ role Worker { can execute }
5
+
6
+ agent Assistant : Worker {
7
+ llm default = { provider: "openai", model: "gpt-5.2" }
8
+
9
+ on test_while(args: Json) {
10
+ playbook """
11
+ Play chess with the user.
12
+ On each turn you show the board, and the user says where to move with a combination like A2 to A4, B3 to C3
13
+ Then you make your move and show the board as it looks after your move.
14
+ End the game when someone wins or if the user expresses their wish to stop.
15
+ """
16
+ }
17
+ }
18
+
19
+ run Assistant.test_while({})
@@ -3,12 +3,12 @@
3
3
  // Simple stateful agent that counts using playbooks
4
4
  // ============================================================
5
5
 
6
- package "demo.koi.counter"
7
-
8
6
  role Worker { can execute }
7
+ role Coordinator { can execute, can delegate }
9
8
 
10
- Agent Counter : Worker {
9
+ agent Counter : Worker {
11
10
  llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 200 }
11
+ amnesia = true
12
12
 
13
13
  state {
14
14
  count: Int = 0
@@ -16,111 +16,62 @@ Agent Counter : Worker {
16
16
 
17
17
  on increment(args: Json) {
18
18
  playbook """
19
- You are a counter agent. Increment the internal counter by 1 and return the new value.
20
-
21
- Current state: state.count = ${state.count}
22
-
23
- Your task:
24
- 1. Calculate the new count by adding 1 to the current count
25
- 2. Return a JSON response with BOTH the result AND the state update
26
-
27
- Return ONLY this exact JSON structure (no markdown, no explanations):
28
- {
29
- "state_updates": {
30
- "count": [new count value after incrementing]
31
- },
32
- "count": [new count value after incrementing]
33
- }
34
-
35
- Example: If current count is 5, return:
36
- {
37
- "state_updates": { "count": 6 },
38
- "count": 6
39
- }
19
+ You are a counter agent. Increment the internal counter by 1.
20
+ Current count: ${state.count}
21
+ Calculate the new count and return it. Use state_updates to persist the new value.
40
22
  """
41
23
  }
42
24
 
43
25
  on get(args: Json) {
44
26
  playbook """
45
27
  You are a counter agent. Return the current counter value without modifying it.
46
-
47
- Current state: state.count = ${state.count}
48
-
49
- Return ONLY this exact JSON structure (no markdown, no explanations):
50
- {
51
- "count": ${state.count}
52
- }
28
+ Current count: ${state.count}
53
29
  """
54
30
  }
55
31
 
56
32
  on reset(args: Json) {
57
33
  playbook """
58
34
  You are a counter agent. Reset the counter to zero.
59
-
60
- Current state: state.count = ${state.count}
61
-
62
- Your task:
63
- 1. Reset the counter to 0
64
- 2. Return a JSON response with BOTH the result AND the state update
65
-
66
- Return ONLY this exact JSON structure (no markdown, no explanations):
67
- {
68
- "state_updates": {
69
- "count": 0
70
- },
71
- "count": 0
72
- }
35
+ Current count: ${state.count}
36
+ Reset to 0 and return. Use state_updates to persist the new value.
73
37
  """
74
38
  }
75
39
 
76
40
  on incrementBy(args: Json) {
77
41
  playbook """
78
42
  You are a counter agent. Increment the counter by a specific amount.
79
-
80
- Current state: state.count = ${state.count}
81
- Amount to increment: args.amount = ${args.amount || 1}
82
-
83
- Your task:
84
- 1. Calculate the new count by adding args.amount to the current count
85
- 2. Return a JSON response with BOTH the result AND the state update
86
-
87
- Return ONLY this exact JSON structure (no markdown, no explanations):
88
- {
89
- "state_updates": {
90
- "count": [new count value]
91
- },
92
- "count": [new count value],
93
- "incremented": [amount that was added]
94
- }
43
+ Current count: ${state.count}
44
+ Amount to add: ${args.amount || 1}
45
+ Calculate the new count and return it. Use state_updates to persist the new value.
95
46
  """
96
47
  }
97
48
  }
98
49
 
99
- Team CounterTeam {
100
- counter = Counter
50
+ team CounterTeam {
51
+ counter: Counter
101
52
  }
102
53
 
103
- Agent Orchestrator : Worker {
104
- uses Team CounterTeam
54
+ agent Orchestrator : Coordinator {
55
+ uses team CounterTeam
105
56
 
106
57
  on start(args: Json) {
107
58
  console.log("🔢 Counter Test Starting...")
108
59
  console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
109
60
 
110
61
  const r1 =
111
- await send peers.event("increment").role(Worker).any()({}) timeout 5s
62
+ await send peers.event("increment").role(Worker).any()({}) timeout 30s
112
63
  console.log("✓ After increment 1:", r1)
113
64
 
114
65
  const r2 =
115
- await send peers.event("increment").role(Worker).any()({}) timeout 5s
66
+ await send peers.event("increment").role(Worker).any()({}) timeout 305s
116
67
  console.log("✓ After increment 2:", r2)
117
68
 
118
69
  const r3 =
119
- await send peers.event("increment").role(Worker).any()({}) timeout 5s
70
+ await send peers.event("increment").role(Worker).any()({}) timeout 305s
120
71
  console.log("✓ After increment 3:", r3)
121
72
 
122
73
  const current =
123
- await send peers.event("get").role(Worker).any()({}) timeout 5s
74
+ await send peers.event("get").role(Worker).any()({}) timeout 30s
124
75
  console.log("✓ Current value:", current)
125
76
 
126
77
  console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
@@ -1,10 +1,15 @@
1
- package "test.delegation"
2
-
3
1
  role Worker { can execute }
2
+ role Coordinator { can execute, can delegate }
3
+
4
+ team TestTeam {
5
+ translator: Translator
6
+ wordCounter: WordCounter
7
+ }
4
8
 
5
9
  // Simple translator agent
6
- Agent Translator : Worker {
10
+ agent Translator : Worker {
7
11
  llm default = { provider: "openai", model: "gpt-4o-mini" }
12
+ amnesia = true
8
13
 
9
14
  on translate(args: Json) {
10
15
  playbook """
@@ -15,8 +20,9 @@ Agent Translator : Worker {
15
20
  }
16
21
 
17
22
  // Simple counter agent
18
- Agent WordCounter : Worker {
23
+ agent WordCounter : Worker {
19
24
  llm default = { provider: "openai", model: "gpt-4o-mini" }
25
+ amnesia = true
20
26
 
21
27
  on count(args: Json) {
22
28
  playbook """
@@ -27,24 +33,16 @@ Agent WordCounter : Worker {
27
33
  }
28
34
 
29
35
  // Orchestrator that chains tasks
30
- Agent Orchestrator : Worker {
36
+ agent Orchestrator : Coordinator {
31
37
  llm default = { provider: "openai", model: "gpt-4o-mini" }
38
+ uses team TestTeam
32
39
 
33
40
  on processText(args: Json) {
34
41
  playbook """
35
- Task: Translate "${args.text}" to Spanish, then count the words.
36
-
37
- Create a plan with 2 actions:
38
- 1. Translate the text to Spanish
39
- 2. Count the words in the translation
40
-
41
- Return JSON with actions array:
42
- {
43
- "actions": [
44
- { "intent": "translate to spanish", "data": { "text": "${args.text}", "language": "spanish" } },
45
- { "intent": "count words", "data": { "text": "\${previousResult.translated}" } }
46
- ]
47
- }
42
+ Prompt the user to enter a sentence.
43
+ Translate the sentence to Spanish.
44
+ Count the words in the translation.
45
+ Print the original sentence, the translation, and the word count.
48
46
  """
49
47
  }
50
48
  }
@@ -0,0 +1,20 @@
1
+ // Demo: Iteration Actions (repeat and while)
2
+ // Shows how to repeat actions fixed number of times or until condition
3
+
4
+ role Worker { can execute }
5
+
6
+ agent Assistant : Worker {
7
+ llm default = { provider: "openai", model: "gpt-5.2" }
8
+
9
+ on test_while(args: Json) {
10
+ playbook """
11
+ Talk with the user until they say goodbye to you.
12
+ Start the conversation by bringing up a topic of general interest, about politics, sports, science, whatever you prefer.
13
+ Talk with the user until they express their intention to end the conversation, in which case say goodbye cordially and end the conversation.
14
+ When you ask the user something, let them express themselves. Do not give them a set of options, instead let them express themselves freely.
15
+ SUPER IMPORTANT, The first thing you must do is introduce yourself. Your name is Koi, so ask for their name and greet them cordially. Then start the conversation.
16
+ """
17
+ }
18
+ }
19
+
20
+ run Assistant.test_while({})
@@ -1,52 +1,16 @@
1
- // ============================================================
2
- // Koi Hello World with LLM Playbook
3
- // Simple example showing playbook execution with real LLM
4
- // ============================================================
5
-
6
- package "demo.koi.helloworld"
1
+ // Demo: Iteration Actions (repeat and while)
2
+ // Shows how to repeat actions fixed number of times or until condition
7
3
 
8
4
  role Worker { can execute }
9
5
 
10
- // Agent with playbook only (will execute with LLM)
11
- Agent Greeter : Worker {
12
- llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.7, max_tokens: 200 }
6
+ agent Assistant : Worker {
7
+ llm default = { provider: "openai", model: "gpt-5.2" }
13
8
 
14
- on greet(args: Json) {
9
+ on test_while(args: Json) {
15
10
  playbook """
16
- You are a friendly greeter. Generate a warm, creative greeting for the person whose name is in args.name.
17
-
18
- Return a JSON object with this exact structure:
19
- {
20
- "greeting": "Your creative greeting here",
21
- "language": "english",
22
- "style": "friendly"
23
- }
24
-
25
- Make the greeting unique and warm, but keep it under 50 words.
11
+ Ask the user for their name, then greet them warmly
26
12
  """
27
13
  }
28
14
  }
29
15
 
30
- Team HelloTeam {
31
- greeter = Greeter
32
- }
33
-
34
- // Orchestrator with procedural code
35
- Agent Orchestrator : Worker {
36
- uses Team HelloTeam
37
-
38
- on start(args: Json) {
39
- const name = args.name
40
-
41
- const result =
42
- await send peers.event("greet").role(Worker).any()({ name: name }) timeout 30s
43
-
44
- return {
45
- success: true,
46
- name: name,
47
- response: result
48
- }
49
- }
50
- }
51
-
52
- run Orchestrator.start({ name: "World" })
16
+ run Assistant.test_while({})
@@ -0,0 +1,29 @@
1
+ // ============================================================
2
+ // Koi — MCP Stdio Server Demo
3
+ // Demonstrates connecting to external MCP servers via stdio
4
+ // ============================================================
5
+
6
+ role Worker { can execute }
7
+
8
+ // Declare an MCP server that communicates via stdio
9
+ // The server is spawned as a subprocess and tools are discovered via JSON-RPC 2.0
10
+ mcp echoServer = {
11
+ command: "node",
12
+ args: ["examples/utils/echo-mcp-server.js"]
13
+ }
14
+
15
+ // Agent that uses the MCP server's tools
16
+ agent MCPAgent : Worker {
17
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
18
+ uses mcp echoServer
19
+
20
+ on testEcho(args: Json) {
21
+ playbook """
22
+ Use the echo MCP server to echo back the message: "${args.message}"
23
+ Then print the result.
24
+ Return the echo result.
25
+ """
26
+ }
27
+ }
28
+
29
+ run MCPAgent.testEcho({ message: "Hello from Koi MCP!" })
@@ -0,0 +1,49 @@
1
+ role Worker { can execute }
2
+ role Coordinator { can execute, can delegate }
3
+
4
+ team MemoryTeam {
5
+ assistant: MemoryAssistant
6
+ }
7
+
8
+ // Agent that should remember previous interactions
9
+ agent MemoryAssistant : Worker {
10
+ llm default = { provider: "openai", model: "gpt-5.2" }
11
+
12
+ on ask(args: Json) {
13
+ playbook """
14
+ ${args.question}
15
+
16
+ IMPORTANT: If you have memory of previous conversations, EXPLICITLY mention what you were asked before and what you answered.
17
+ If it's your first time, say that this is your first interaction.
18
+
19
+ Respond in English, maximum 2 sentences.
20
+
21
+ Return ONLY: { "answer": "your response here" }
22
+ """
23
+ }
24
+ }
25
+
26
+ // Coordinator that calls the assistant 3 times to test memory
27
+ agent MemoryCoordinator : Coordinator {
28
+ llm default = { provider: "openai", model: "gpt-5.2" }
29
+
30
+ uses team MemoryTeam
31
+
32
+ on start(args: Json) {
33
+ playbook """
34
+ You will ask the MemoryAssistant 3 questions, one by one, to check if it remembers the previous ones.
35
+
36
+ 1. Ask it: "What is the capital of France?"
37
+ 2. Print its response with: Response 1: <response>
38
+ 3. Ask it: "And the capital of Germany?"
39
+ 4. Print its response with: Response 2: <response>
40
+ 5. Ask it: "What have I asked you before? List the previous questions and your answers."
41
+ 6. Print its response with: Response 3 (memory test): <response>
42
+
43
+ At the end print:
44
+ Memory test completed
45
+ """
46
+ }
47
+ }
48
+
49
+ run MemoryCoordinator.start({})
@@ -0,0 +1,32 @@
1
+ // ============================================================
2
+ // Koi — Mobile MCP Demo
3
+ // Controls a mobile device via the mobile-mcps MCP server.
4
+ // Requires: Android emulator/device or iOS simulator running.
5
+ // Usage: GEMINI_API_KEY=... koi run examples/mobile-mcp-demo.koi
6
+ // ============================================================
7
+
8
+ role Worker { can execute }
9
+
10
+ mcp mobile = {
11
+ command: "node",
12
+ args: ["/path/to/mcp-server.js"],
13
+ //env: { "GEMINI_API_KEY": "" }
14
+ }
15
+
16
+ agent MobileAgent : Worker {
17
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
18
+ uses mcp mobile
19
+
20
+ on automate(args: Json) {
21
+ playbook """
22
+ Automate the mobile device to accomplish this goal: "${args.goal}"
23
+ 1. List available devices to find a target.
24
+ 2. Start the agent with the goal on the first available device.
25
+ 3. Return the agent result.
26
+ """
27
+ }
28
+ }
29
+
30
+ run MobileAgent.automate({ goal: "Open maps and search for Rome, then in Rome find the street where the Trevi Fountain is located and show a photo" })
31
+
32
+