@koi-language/koi 1.0.5 → 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.
- package/README.md +4 -125
- package/examples/.build/agent-dialogue.ts +138 -0
- package/examples/.build/agent-dialogue.ts.map +1 -0
- package/examples/.build/chess.ts +77 -0
- package/examples/.build/chess.ts.map +1 -0
- package/examples/.build/delegation-test.ts +140 -0
- package/examples/.build/delegation-test.ts.map +1 -0
- package/examples/.build/dialog-demo.ts +77 -0
- package/examples/.build/dialog-demo.ts.map +1 -0
- package/examples/.build/hello-world.ts +77 -0
- package/examples/.build/hello-world.ts.map +1 -0
- package/examples/.build/lover-dialog-demo.ts +77 -0
- package/examples/.build/lover-dialog-demo.ts.map +1 -0
- package/examples/.build/package.json +3 -0
- package/examples/.build/registry-interactive-demo.ts +202 -0
- package/examples/.build/registry-interactive-demo.ts.map +1 -0
- package/examples/.build/registry-playbook-demo.ts +201 -0
- package/examples/.build/registry-playbook-demo.ts.map +1 -0
- package/examples/.build/tic-tac-toe.ts +77 -0
- package/examples/.build/tic-tac-toe.ts.map +1 -0
- package/examples/actions-demo.koi +8 -9
- package/examples/activists-dialogue.koi +75 -0
- package/examples/agent-dialogue.koi +66 -0
- package/examples/chess.koi +19 -0
- package/examples/counter.koi +20 -69
- package/examples/delegation-test.koi +16 -18
- package/examples/dialog-demo.koi +20 -0
- package/examples/hello-world.koi +7 -43
- package/examples/mcp-stdio-demo.koi +29 -0
- package/examples/memory-test.koi +49 -0
- package/examples/mobile-mcp-demo.koi +32 -0
- package/examples/multi-event-handler-test.koi +16 -18
- package/examples/pipeline.koi +15 -17
- package/examples/prompt-demo.koi +20 -0
- package/examples/{registry-playbook-email-compositor.koi → registry-interactive-demo.koi} +27 -27
- package/examples/registry-playbook-demo.koi +28 -28
- package/examples/skill-import-test.koi +7 -9
- package/examples/skills/.build/math-operations.ts +1656 -0
- package/examples/skills/.build/math-operations.ts.map +1 -0
- package/examples/skills/.build/package.json +3 -0
- package/examples/skills/.build/string-operations.ts +1643 -0
- package/examples/skills/.build/string-operations.ts.map +1 -0
- package/examples/skills/advanced/.build/index.ts +3223 -0
- package/examples/skills/advanced/.build/index.ts.map +1 -0
- package/examples/skills/advanced/.build/package.json +3 -0
- package/examples/skills/advanced/index.koi +3 -5
- package/examples/skills/math-operations.koi +1 -3
- package/examples/skills/string-operations.koi +1 -3
- package/examples/tic-tac-toe.koi +19 -0
- package/examples/utils/echo-mcp-server.js +141 -0
- package/examples/web-delegation-demo.koi +15 -17
- package/package.json +2 -1
- package/src/cli/koi.js +30 -41
- package/src/compiler/build-optimizer.js +204 -289
- package/src/compiler/cache-manager.js +1 -1
- package/src/compiler/import-resolver.js +5 -9
- package/src/compiler/parser.js +6072 -3476
- package/src/compiler/transpiler.js +346 -38
- package/src/grammar/koi.pegjs +302 -62
- package/src/runtime/actions/{format.js → call-llm.js} +37 -44
- package/src/runtime/actions/call-mcp.js +97 -0
- package/src/runtime/actions/if.js +179 -0
- package/src/runtime/actions/print.js +3 -1
- package/src/runtime/actions/prompt-user.js +75 -0
- package/src/runtime/actions/repeat.js +147 -0
- package/src/runtime/actions/shell.js +185 -0
- package/src/runtime/actions/while.js +205 -0
- package/src/runtime/agent.js +592 -178
- package/src/runtime/cli-display.js +26 -0
- package/src/runtime/cli-input.js +421 -0
- package/src/runtime/cli-logger.js +2 -5
- package/src/runtime/cli-markdown.js +61 -0
- package/src/runtime/cli-select.js +106 -0
- package/src/runtime/incremental-json-parser.js +51 -17
- package/src/runtime/index.js +1 -0
- package/src/runtime/llm-provider.js +1083 -572
- package/src/runtime/mcp-registry.js +141 -0
- package/src/runtime/mcp-stdio-client.js +334 -0
- package/src/runtime/planner.js +1 -1
- package/src/runtime/playbook-session.js +259 -0
- package/src/runtime/registry-backends/keyv-sqlite.js +1 -1
- package/src/runtime/registry-backends/local.js +1 -1
- package/src/runtime/router.js +22 -26
- package/src/runtime/runtime.js +7 -1
- package/examples/cache-test.koi +0 -29
- package/examples/calculator.koi +0 -61
- package/examples/clear-registry.js +0 -33
- package/examples/clear-registry.koi +0 -30
- package/examples/code-introspection-test.koi +0 -149
- package/examples/directory-import-test.koi +0 -84
- package/examples/hello-world-claude.koi +0 -52
- package/examples/hello.koi +0 -24
- package/examples/mcp-example.koi +0 -70
- package/examples/new-import-test.koi +0 -89
- package/examples/registry-demo.koi +0 -184
- package/examples/registry-playbook-email-compositor-2.koi +0 -140
- package/examples/sentiment.koi +0 -90
- package/examples/simple.koi +0 -48
- package/examples/task-chaining-demo.koi +0 -244
- package/examples/test-await.koi +0 -22
- package/examples/test-crypto-sha256.koi +0 -196
- package/examples/test-delegation.koi +0 -41
- package/examples/test-multi-team-routing.koi +0 -258
- package/examples/test-no-handler.koi +0 -35
- package/examples/test-npm-import.koi +0 -67
- package/examples/test-parse.koi +0 -10
- package/examples/test-peers-with-team.koi +0 -59
- package/examples/test-permissions-fail.koi +0 -20
- package/examples/test-permissions.koi +0 -36
- package/examples/test-simple-registry.koi +0 -31
- package/examples/test-typescript-import.koi +0 -64
- package/examples/test-uses-team-syntax.koi +0 -25
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
132
|
-
logger
|
|
133
|
-
processor
|
|
130
|
+
team LoggingTeam {
|
|
131
|
+
logger: Logger
|
|
132
|
+
processor: TaskProcessor
|
|
134
133
|
}
|
|
135
134
|
|
|
136
|
-
|
|
137
|
-
uses
|
|
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({})
|
package/examples/counter.koi
CHANGED
|
@@ -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
|
-
|
|
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
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
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
|
-
|
|
81
|
-
|
|
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
|
-
|
|
100
|
-
counter
|
|
50
|
+
team CounterTeam {
|
|
51
|
+
counter: Counter
|
|
101
52
|
}
|
|
102
53
|
|
|
103
|
-
|
|
104
|
-
uses
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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({})
|
package/examples/hello-world.koi
CHANGED
|
@@ -1,52 +1,16 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
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
|
-
|
|
11
|
-
|
|
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
|
|
9
|
+
on test_while(args: Json) {
|
|
15
10
|
playbook """
|
|
16
|
-
|
|
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
|
-
|
|
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
|
+
|