@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.
- package/QUICKSTART.md +89 -0
- package/README.md +545 -0
- package/examples/actions-demo.koi +177 -0
- package/examples/cache-test.koi +29 -0
- package/examples/calculator.koi +61 -0
- package/examples/clear-registry.js +33 -0
- package/examples/clear-registry.koi +30 -0
- package/examples/code-introspection-test.koi +149 -0
- package/examples/counter.koi +132 -0
- package/examples/delegation-test.koi +52 -0
- package/examples/directory-import-test.koi +84 -0
- package/examples/hello-world-claude.koi +52 -0
- package/examples/hello-world.koi +52 -0
- package/examples/hello.koi +24 -0
- package/examples/mcp-example.koi +70 -0
- package/examples/multi-event-handler-test.koi +144 -0
- package/examples/new-import-test.koi +89 -0
- package/examples/pipeline.koi +162 -0
- package/examples/registry-demo.koi +184 -0
- package/examples/registry-playbook-demo.koi +162 -0
- package/examples/registry-playbook-email-compositor-2.koi +140 -0
- package/examples/registry-playbook-email-compositor.koi +140 -0
- package/examples/sentiment.koi +90 -0
- package/examples/simple.koi +48 -0
- package/examples/skill-import-test.koi +76 -0
- package/examples/skills/advanced/index.koi +95 -0
- package/examples/skills/math-operations.koi +69 -0
- package/examples/skills/string-operations.koi +56 -0
- package/examples/task-chaining-demo.koi +244 -0
- package/examples/test-await.koi +22 -0
- package/examples/test-crypto-sha256.koi +196 -0
- package/examples/test-delegation.koi +41 -0
- package/examples/test-multi-team-routing.koi +258 -0
- package/examples/test-no-handler.koi +35 -0
- package/examples/test-npm-import.koi +67 -0
- package/examples/test-parse.koi +10 -0
- package/examples/test-peers-with-team.koi +59 -0
- package/examples/test-permissions-fail.koi +20 -0
- package/examples/test-permissions.koi +36 -0
- package/examples/test-simple-registry.koi +31 -0
- package/examples/test-typescript-import.koi +64 -0
- package/examples/test-uses-team-syntax.koi +25 -0
- package/examples/test-uses-team.koi +31 -0
- package/examples/utils/calculator.test.ts +144 -0
- package/examples/utils/calculator.ts +56 -0
- package/examples/utils/math-helpers.js +50 -0
- package/examples/utils/math-helpers.ts +55 -0
- package/examples/web-delegation-demo.koi +165 -0
- package/package.json +78 -0
- package/src/cli/koi.js +793 -0
- package/src/compiler/build-optimizer.js +447 -0
- package/src/compiler/cache-manager.js +274 -0
- package/src/compiler/import-resolver.js +369 -0
- package/src/compiler/parser.js +7542 -0
- package/src/compiler/transpiler.js +1105 -0
- package/src/compiler/typescript-transpiler.js +148 -0
- package/src/grammar/koi.pegjs +767 -0
- package/src/runtime/action-registry.js +172 -0
- package/src/runtime/actions/call-skill.js +45 -0
- package/src/runtime/actions/format.js +115 -0
- package/src/runtime/actions/print.js +42 -0
- package/src/runtime/actions/registry-delete.js +37 -0
- package/src/runtime/actions/registry-get.js +37 -0
- package/src/runtime/actions/registry-keys.js +33 -0
- package/src/runtime/actions/registry-search.js +34 -0
- package/src/runtime/actions/registry-set.js +50 -0
- package/src/runtime/actions/return.js +31 -0
- package/src/runtime/actions/send-message.js +58 -0
- package/src/runtime/actions/update-state.js +36 -0
- package/src/runtime/agent.js +1368 -0
- package/src/runtime/cli-logger.js +205 -0
- package/src/runtime/incremental-json-parser.js +201 -0
- package/src/runtime/index.js +33 -0
- package/src/runtime/llm-provider.js +1372 -0
- package/src/runtime/mcp-client.js +1171 -0
- package/src/runtime/planner.js +273 -0
- package/src/runtime/registry-backends/keyv-sqlite.js +215 -0
- package/src/runtime/registry-backends/local.js +260 -0
- package/src/runtime/registry.js +162 -0
- package/src/runtime/role.js +14 -0
- package/src/runtime/router.js +395 -0
- package/src/runtime/runtime.js +113 -0
- package/src/runtime/skill-selector.js +173 -0
- package/src/runtime/skill.js +25 -0
- package/src/runtime/team.js +162 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Actions Demo
|
|
3
|
+
// Demonstrates playbook-based action system:
|
|
4
|
+
// - update_state: Modify agent state
|
|
5
|
+
// - call_skill: Execute skills
|
|
6
|
+
// - send_message: Send events to peers
|
|
7
|
+
// - return: Return results
|
|
8
|
+
// ============================================================
|
|
9
|
+
|
|
10
|
+
package "demo.koi.actions"
|
|
11
|
+
|
|
12
|
+
role Worker { can execute }
|
|
13
|
+
role LoggerRole { can execute }
|
|
14
|
+
|
|
15
|
+
Agent Logger : LoggerRole {
|
|
16
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 150 }
|
|
17
|
+
|
|
18
|
+
state {
|
|
19
|
+
logCount: Int = 0
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
on log(args: Json) {
|
|
23
|
+
playbook """
|
|
24
|
+
You are a logger agent. Increment the log count and return confirmation.
|
|
25
|
+
|
|
26
|
+
Current logCount: ${state.logCount}
|
|
27
|
+
Message to log: ${JSON.stringify(args)}
|
|
28
|
+
|
|
29
|
+
Return this JSON with state_updates:
|
|
30
|
+
{
|
|
31
|
+
"state_updates": {
|
|
32
|
+
"logCount": [logCount + 1]
|
|
33
|
+
},
|
|
34
|
+
"logged": true,
|
|
35
|
+
"count": [new logCount]
|
|
36
|
+
}
|
|
37
|
+
"""
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
on getLogs(args: Json) {
|
|
41
|
+
playbook """
|
|
42
|
+
Return the current log count.
|
|
43
|
+
|
|
44
|
+
Current logCount: ${state.logCount}
|
|
45
|
+
|
|
46
|
+
Return ONLY:
|
|
47
|
+
{
|
|
48
|
+
"count": ${state.logCount}
|
|
49
|
+
}
|
|
50
|
+
"""
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
Agent TaskProcessor : Worker {
|
|
55
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.2, max_tokens: 300 }
|
|
56
|
+
|
|
57
|
+
state {
|
|
58
|
+
tasksProcessed: Int = 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
on processTask(args: Json) {
|
|
62
|
+
playbook """
|
|
63
|
+
You are a task processing agent. Process the incoming task and execute actions.
|
|
64
|
+
|
|
65
|
+
Current state:
|
|
66
|
+
- tasksProcessed: ${state.tasksProcessed}
|
|
67
|
+
|
|
68
|
+
Incoming task: ${JSON.stringify(args)}
|
|
69
|
+
|
|
70
|
+
Your job is to plan and return a list of actions to:
|
|
71
|
+
1. Update the state (increment tasksProcessed)
|
|
72
|
+
2. Return the final result
|
|
73
|
+
|
|
74
|
+
Return ONLY this exact JSON structure (no markdown, no explanations):
|
|
75
|
+
{
|
|
76
|
+
"actions": [
|
|
77
|
+
{
|
|
78
|
+
"type": "update_state",
|
|
79
|
+
"updates": {
|
|
80
|
+
"tasksProcessed": [current tasksProcessed + 1]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"type": "return",
|
|
85
|
+
"data": {
|
|
86
|
+
"success": true,
|
|
87
|
+
"task": "[task description from args.task]",
|
|
88
|
+
"tasksProcessed": [new count]
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Example if args = {"task": "analyze data", "priority": "high"}:
|
|
95
|
+
{
|
|
96
|
+
"actions": [
|
|
97
|
+
{
|
|
98
|
+
"type": "update_state",
|
|
99
|
+
"updates": {
|
|
100
|
+
"tasksProcessed": 1
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"type": "return",
|
|
105
|
+
"data": {
|
|
106
|
+
"success": true,
|
|
107
|
+
"task": "analyze data",
|
|
108
|
+
"tasksProcessed": 1
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
"""
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
on getStatus(args: Json) {
|
|
117
|
+
playbook """
|
|
118
|
+
Return the current status of the task processor.
|
|
119
|
+
|
|
120
|
+
Current state:
|
|
121
|
+
- tasksProcessed: ${state.tasksProcessed}
|
|
122
|
+
|
|
123
|
+
Return ONLY:
|
|
124
|
+
{
|
|
125
|
+
"tasksProcessed": ${state.tasksProcessed}
|
|
126
|
+
}
|
|
127
|
+
"""
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
Team LoggingTeam {
|
|
132
|
+
logger = Logger
|
|
133
|
+
processor = TaskProcessor
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
Agent Orchestrator : Worker {
|
|
137
|
+
uses Team LoggingTeam
|
|
138
|
+
|
|
139
|
+
on start(args: Json) {
|
|
140
|
+
console.log("🎯 Actions Demo Starting...")
|
|
141
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
142
|
+
|
|
143
|
+
// Process first task
|
|
144
|
+
console.log("\n📋 Processing Task 1: Analyze User Data")
|
|
145
|
+
const task1 =
|
|
146
|
+
await send peers.event("processTask").role(Worker).any()({
|
|
147
|
+
task: "analyze user data",
|
|
148
|
+
priority: "high"
|
|
149
|
+
}) timeout 15s
|
|
150
|
+
console.log("✓ Task 1 result:", task1)
|
|
151
|
+
|
|
152
|
+
// Process second task
|
|
153
|
+
console.log("\n📋 Processing Task 2: Generate Report")
|
|
154
|
+
const task2 =
|
|
155
|
+
await send peers.event("processTask").role(Worker).any()({
|
|
156
|
+
task: "generate monthly report",
|
|
157
|
+
priority: "medium"
|
|
158
|
+
}) timeout 15s
|
|
159
|
+
console.log("✓ Task 2 result:", task2)
|
|
160
|
+
|
|
161
|
+
// Get processor status
|
|
162
|
+
console.log("\n📊 Getting processor status...")
|
|
163
|
+
const status =
|
|
164
|
+
await send peers.event("getStatus").role(Worker).any()({}) timeout 10s
|
|
165
|
+
console.log("✓ Status:", status)
|
|
166
|
+
|
|
167
|
+
console.log("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
168
|
+
return {
|
|
169
|
+
message: "Actions demo complete ✓",
|
|
170
|
+
summary: {
|
|
171
|
+
tasksProcessed: status.tasksProcessed
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
run Orchestrator.start({})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Cache Test Example
|
|
2
|
+
package "test.cache"
|
|
3
|
+
|
|
4
|
+
role Worker { can execute }
|
|
5
|
+
|
|
6
|
+
Agent TextTranslator : Worker {
|
|
7
|
+
llm default = { provider: "openai", model: "gpt-4o-mini" }
|
|
8
|
+
|
|
9
|
+
on translate(args: Json) {
|
|
10
|
+
playbook """
|
|
11
|
+
Translate this text to the target language: ${args.text}
|
|
12
|
+
Target language: ${args.language}
|
|
13
|
+
Return JSON with translated text.
|
|
14
|
+
"""
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Agent WordAnalyzer : Worker {
|
|
19
|
+
llm default = { provider: "openai", model: "gpt-4o-mini" }
|
|
20
|
+
|
|
21
|
+
on analyze(args: Json) {
|
|
22
|
+
playbook """
|
|
23
|
+
Analyze this text and count words: ${args.text}
|
|
24
|
+
Return JSON with word count and analysis.
|
|
25
|
+
"""
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
run TextTranslator.translate({ text: "hello", language: "spanish" })
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Calculator Example
|
|
3
|
+
// Simple calculator with multiple operations (procedural code only)
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.calculator"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
|
|
10
|
+
// All handlers use procedural code (no playbooks)
|
|
11
|
+
Agent Calculator : Worker {
|
|
12
|
+
on add(args: Json) {
|
|
13
|
+
const a = args.a
|
|
14
|
+
const b = args.b
|
|
15
|
+
return { result: a + b, operation: "add" }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
on multiply(args: Json) {
|
|
19
|
+
const a = args.a
|
|
20
|
+
const b = args.b
|
|
21
|
+
return { result: a * b, operation: "multiply" }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
on divide(args: Json) {
|
|
25
|
+
const a = args.a
|
|
26
|
+
const b = args.b
|
|
27
|
+
|
|
28
|
+
if b == 0 {
|
|
29
|
+
return { error: "Division by zero", operation: "divide" }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { result: a / b, operation: "divide" }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Team CalcTeam {
|
|
37
|
+
calc = Calculator
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Agent Orchestrator : Worker {
|
|
41
|
+
uses Team CalcTeam
|
|
42
|
+
|
|
43
|
+
on start(args: Json) {
|
|
44
|
+
const sum =
|
|
45
|
+
await send peers.event("add").role(Worker).any()({ a: 10, b: 5 }) timeout 2s
|
|
46
|
+
|
|
47
|
+
const product =
|
|
48
|
+
await send peers.event("multiply").role(Worker).any()({ a: 10, b: 5 }) timeout 2s
|
|
49
|
+
|
|
50
|
+
const quotient =
|
|
51
|
+
await send peers.event("divide").role(Worker).any()({ a: 10, b: 5 }) timeout 2s
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
sum: sum,
|
|
55
|
+
product: product,
|
|
56
|
+
quotient: quotient
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
run Orchestrator.start({})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Clear Registry - Delete all data from the registry
|
|
4
|
+
import { registry } from '../src/runtime/index.js';
|
|
5
|
+
|
|
6
|
+
async function clearRegistry() {
|
|
7
|
+
console.log("⚠️ WARNING: Clearing all registry data...");
|
|
8
|
+
console.log("");
|
|
9
|
+
|
|
10
|
+
// Show stats before clearing
|
|
11
|
+
const statsBefore = await registry.stats();
|
|
12
|
+
console.log(" Current entries:", statsBefore.count);
|
|
13
|
+
console.log(" Storage:", statsBefore.file);
|
|
14
|
+
console.log("");
|
|
15
|
+
|
|
16
|
+
// Clear the registry
|
|
17
|
+
await registry.clear();
|
|
18
|
+
|
|
19
|
+
console.log("✅ Registry cleared successfully!");
|
|
20
|
+
console.log("");
|
|
21
|
+
|
|
22
|
+
// Show stats after clearing
|
|
23
|
+
const statsAfter = await registry.stats();
|
|
24
|
+
console.log(" Entries remaining:", statsAfter.count);
|
|
25
|
+
console.log("");
|
|
26
|
+
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
clearRegistry().catch((error) => {
|
|
31
|
+
console.error("❌ Error clearing registry:", error.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Clear Registry - Delete all data from the registry
|
|
2
|
+
package "clear.registry"
|
|
3
|
+
|
|
4
|
+
role Admin { can execute }
|
|
5
|
+
|
|
6
|
+
Agent Cleaner : Admin {
|
|
7
|
+
on clearAll(args: Json) {
|
|
8
|
+
console.log("⚠️ WARNING: Clearing all registry data...")
|
|
9
|
+
|
|
10
|
+
// Show current stats before clearing
|
|
11
|
+
const statsBefore = await registry.stats()
|
|
12
|
+
console.log(" Current entries:", statsBefore.count)
|
|
13
|
+
console.log(" Storage:", statsBefore.file)
|
|
14
|
+
console.log("")
|
|
15
|
+
|
|
16
|
+
// Clear the registry
|
|
17
|
+
await registry.clear()
|
|
18
|
+
|
|
19
|
+
console.log("✅ Registry cleared successfully!")
|
|
20
|
+
|
|
21
|
+
// Show stats after clearing
|
|
22
|
+
const statsAfter = await registry.stats()
|
|
23
|
+
console.log(" Entries remaining:", statsAfter.count)
|
|
24
|
+
console.log("")
|
|
25
|
+
|
|
26
|
+
return { success: true, clearedCount: statsBefore.count }
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
run Cleaner.clearAll({})
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
package "demo.code.introspection"
|
|
2
|
+
|
|
3
|
+
role Calculator { can calculate }
|
|
4
|
+
role Coordinator { can coordinate }
|
|
5
|
+
|
|
6
|
+
// Agent con event handler que tiene código (no playbook)
|
|
7
|
+
// El sistema debe hacer introspección para generar affordance
|
|
8
|
+
Agent MathProcessor : Calculator {
|
|
9
|
+
llm default = {
|
|
10
|
+
provider: "openai",
|
|
11
|
+
model: "gpt-4o-mini",
|
|
12
|
+
temperature: 0.1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Event handler con código Koi (sin playbook)
|
|
16
|
+
// El sistema hará introspección del código para generar affordance
|
|
17
|
+
// Este handler suma todos los números en el array
|
|
18
|
+
on calculateSum(args: Json) {
|
|
19
|
+
const numbers = args.numbers
|
|
20
|
+
|
|
21
|
+
// Procesar números y sumarlos
|
|
22
|
+
const result = await send peers.event("sumArray").role(Calculator).any()({
|
|
23
|
+
data: numbers
|
|
24
|
+
}) timeout 5s
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
operation: "sum",
|
|
28
|
+
result: result
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Event handler que multiplica todos los números
|
|
33
|
+
on calculateProduct(args: Json) {
|
|
34
|
+
const numbers = args.numbers
|
|
35
|
+
|
|
36
|
+
// Multiplicar los números usando delegación
|
|
37
|
+
const result = await send peers.event("multiplyArray").role(Calculator).any()({
|
|
38
|
+
data: numbers
|
|
39
|
+
}) timeout 5s
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
operation: "product",
|
|
43
|
+
result: result
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Event handler con playbook (para comparar)
|
|
48
|
+
on calculateAverage(args: Json) {
|
|
49
|
+
playbook """
|
|
50
|
+
Calculate the average of ${JSON.stringify(args.numbers)}
|
|
51
|
+
|
|
52
|
+
Sum all numbers and divide by count.
|
|
53
|
+
Return: { "operation": "average", "result": <value> }
|
|
54
|
+
"""
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
Team MathTeam {
|
|
59
|
+
processor = MathProcessor
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Coordinator que delega basándose en affordances
|
|
63
|
+
Agent Coordinator : Coordinator {
|
|
64
|
+
llm default = {
|
|
65
|
+
provider: "openai",
|
|
66
|
+
model: "gpt-4o-mini",
|
|
67
|
+
temperature: 0.1
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
uses Team MathTeam
|
|
71
|
+
|
|
72
|
+
on process(args: Json) {
|
|
73
|
+
playbook """
|
|
74
|
+
Process this math request: ${JSON.stringify(args)}
|
|
75
|
+
|
|
76
|
+
Available operations (delegate to Calculator role):
|
|
77
|
+
- Calculate sum/total of numbers
|
|
78
|
+
- Calculate product/multiplication of numbers
|
|
79
|
+
- Calculate average/mean of numbers
|
|
80
|
+
|
|
81
|
+
Determine the intent and delegate with an action:
|
|
82
|
+
{
|
|
83
|
+
"actions": [{
|
|
84
|
+
"title": "Calculating...",
|
|
85
|
+
"intent": "<your interpretation of what math operation is needed>",
|
|
86
|
+
"data": { "numbers": ${JSON.stringify(args.numbers)} }
|
|
87
|
+
}]
|
|
88
|
+
}
|
|
89
|
+
"""
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Team CoordinatorTeam {
|
|
94
|
+
coordinator = Coordinator
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Agent Main : Coordinator {
|
|
98
|
+
uses Team CoordinatorTeam
|
|
99
|
+
|
|
100
|
+
on start(args: Json) {
|
|
101
|
+
console.log("╔════════════════════════════════════════════╗")
|
|
102
|
+
console.log("║ Code Introspection Test ║")
|
|
103
|
+
console.log("║ Event handlers with source code ║")
|
|
104
|
+
console.log("╚════════════════════════════════════════════╝\n")
|
|
105
|
+
|
|
106
|
+
// Test 1: Request sum (should route to calculateSum)
|
|
107
|
+
console.log("📋 Test 1: Calculate the total")
|
|
108
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
109
|
+
|
|
110
|
+
const sumResult =
|
|
111
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
112
|
+
operation: "calculate the total of these numbers",
|
|
113
|
+
numbers: [5, 10, 15, 20]
|
|
114
|
+
}) timeout 30s
|
|
115
|
+
|
|
116
|
+
console.log("Result:", JSON.stringify(sumResult, null, 2))
|
|
117
|
+
|
|
118
|
+
// Test 2: Request product (should route to calculateProduct)
|
|
119
|
+
console.log("\n📋 Test 2: Multiply all numbers")
|
|
120
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
121
|
+
|
|
122
|
+
const productResult =
|
|
123
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
124
|
+
operation: "multiply all the numbers together",
|
|
125
|
+
numbers: [2, 3, 4, 5]
|
|
126
|
+
}) timeout 30s
|
|
127
|
+
|
|
128
|
+
console.log("Result:", JSON.stringify(productResult, null, 2))
|
|
129
|
+
|
|
130
|
+
// Test 3: Request average (should route to calculateAverage with playbook)
|
|
131
|
+
console.log("\n📋 Test 3: Find the average")
|
|
132
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
133
|
+
|
|
134
|
+
const avgResult =
|
|
135
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
136
|
+
operation: "find the average value",
|
|
137
|
+
numbers: [10, 20, 30, 40, 50]
|
|
138
|
+
}) timeout 30s
|
|
139
|
+
|
|
140
|
+
console.log("Result:", JSON.stringify(avgResult, null, 2))
|
|
141
|
+
|
|
142
|
+
return {
|
|
143
|
+
success: true,
|
|
144
|
+
tests_completed: 3
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
run Main.start({})
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Counter Example
|
|
3
|
+
// Simple stateful agent that counts using playbooks
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.counter"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
|
|
10
|
+
Agent Counter : Worker {
|
|
11
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 200 }
|
|
12
|
+
|
|
13
|
+
state {
|
|
14
|
+
count: Int = 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
on increment(args: Json) {
|
|
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
|
+
}
|
|
40
|
+
"""
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
on get(args: Json) {
|
|
44
|
+
playbook """
|
|
45
|
+
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
|
+
}
|
|
53
|
+
"""
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
on reset(args: Json) {
|
|
57
|
+
playbook """
|
|
58
|
+
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
|
+
}
|
|
73
|
+
"""
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
on incrementBy(args: Json) {
|
|
77
|
+
playbook """
|
|
78
|
+
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
|
+
}
|
|
95
|
+
"""
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Team CounterTeam {
|
|
100
|
+
counter = Counter
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
Agent Orchestrator : Worker {
|
|
104
|
+
uses Team CounterTeam
|
|
105
|
+
|
|
106
|
+
on start(args: Json) {
|
|
107
|
+
console.log("🔢 Counter Test Starting...")
|
|
108
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
109
|
+
|
|
110
|
+
const r1 =
|
|
111
|
+
await send peers.event("increment").role(Worker).any()({}) timeout 5s
|
|
112
|
+
console.log("✓ After increment 1:", r1)
|
|
113
|
+
|
|
114
|
+
const r2 =
|
|
115
|
+
await send peers.event("increment").role(Worker).any()({}) timeout 5s
|
|
116
|
+
console.log("✓ After increment 2:", r2)
|
|
117
|
+
|
|
118
|
+
const r3 =
|
|
119
|
+
await send peers.event("increment").role(Worker).any()({}) timeout 5s
|
|
120
|
+
console.log("✓ After increment 3:", r3)
|
|
121
|
+
|
|
122
|
+
const current =
|
|
123
|
+
await send peers.event("get").role(Worker).any()({}) timeout 5s
|
|
124
|
+
console.log("✓ Current value:", current)
|
|
125
|
+
|
|
126
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
127
|
+
|
|
128
|
+
return { message: "Counter test complete ✓", final: current }
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
run Orchestrator.start({})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package "test.delegation"
|
|
2
|
+
|
|
3
|
+
role Worker { can execute }
|
|
4
|
+
|
|
5
|
+
// Simple translator agent
|
|
6
|
+
Agent Translator : Worker {
|
|
7
|
+
llm default = { provider: "openai", model: "gpt-4o-mini" }
|
|
8
|
+
|
|
9
|
+
on translate(args: Json) {
|
|
10
|
+
playbook """
|
|
11
|
+
Translate "${args.text}" to ${args.language}.
|
|
12
|
+
Return JSON: { "translated": "translated text here" }
|
|
13
|
+
"""
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Simple counter agent
|
|
18
|
+
Agent WordCounter : Worker {
|
|
19
|
+
llm default = { provider: "openai", model: "gpt-4o-mini" }
|
|
20
|
+
|
|
21
|
+
on count(args: Json) {
|
|
22
|
+
playbook """
|
|
23
|
+
Count words in: "${args.text}"
|
|
24
|
+
Return JSON: { "wordCount": number }
|
|
25
|
+
"""
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Orchestrator that chains tasks
|
|
30
|
+
Agent Orchestrator : Worker {
|
|
31
|
+
llm default = { provider: "openai", model: "gpt-4o-mini" }
|
|
32
|
+
|
|
33
|
+
on processText(args: Json) {
|
|
34
|
+
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
|
+
}
|
|
48
|
+
"""
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
run Orchestrator.processText({ text: "hello world" })
|