@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,84 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Directory Import Test
|
|
3
|
+
// Tests importing from directories (looks for index.koi)
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.directory"
|
|
7
|
+
|
|
8
|
+
// Import from directory - automatically finds index.koi
|
|
9
|
+
import "./skills/advanced"
|
|
10
|
+
|
|
11
|
+
role Worker { can work }
|
|
12
|
+
|
|
13
|
+
// Agent that uses skills from the directory import
|
|
14
|
+
Agent StatisticsProcessor : Worker {
|
|
15
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 300 }
|
|
16
|
+
uses Skill StatisticalAnalysis
|
|
17
|
+
|
|
18
|
+
on process(args: Json) {
|
|
19
|
+
playbook """
|
|
20
|
+
Process statistical analysis for: ${JSON.stringify(args)}
|
|
21
|
+
|
|
22
|
+
Pass the "numbers" array to the tool and return the result.
|
|
23
|
+
"""
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Team WorkerTeam {
|
|
28
|
+
processor = StatisticsProcessor
|
|
29
|
+
analyzer = DataAnalyzer // Agent from the imported directory
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Demo runner
|
|
33
|
+
Agent DemoRunner : Worker {
|
|
34
|
+
uses Team WorkerTeam
|
|
35
|
+
|
|
36
|
+
on runTest(args: Json) {
|
|
37
|
+
console.log("╔════════════════════════════════════════════╗")
|
|
38
|
+
console.log("║ Directory Import Test ║")
|
|
39
|
+
console.log("║ import \"./skills/advanced\" ║")
|
|
40
|
+
console.log("╚════════════════════════════════════════════╝\n")
|
|
41
|
+
|
|
42
|
+
// Test 1: Calculate mean using skill directly
|
|
43
|
+
console.log("📋 Test 1: Calculate mean of [10, 20, 30, 40, 50]")
|
|
44
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
45
|
+
|
|
46
|
+
const meanResult =
|
|
47
|
+
await send peers.event("process").role(Worker).any()({
|
|
48
|
+
operation: "mean",
|
|
49
|
+
numbers: [10, 20, 30, 40, 50]
|
|
50
|
+
}) timeout 10s
|
|
51
|
+
|
|
52
|
+
console.log("Result:", JSON.stringify(meanResult, null, 2))
|
|
53
|
+
|
|
54
|
+
// Test 2: Calculate median
|
|
55
|
+
console.log("\n📋 Test 2: Calculate median of [1, 3, 5, 7, 9, 11]")
|
|
56
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
57
|
+
|
|
58
|
+
const medianResult =
|
|
59
|
+
await send peers.event("process").role(Worker).any()({
|
|
60
|
+
operation: "median",
|
|
61
|
+
numbers: [1, 3, 5, 7, 9, 11]
|
|
62
|
+
}) timeout 10s
|
|
63
|
+
|
|
64
|
+
console.log("Result:", JSON.stringify(medianResult, null, 2))
|
|
65
|
+
|
|
66
|
+
// Test 3: Use the imported DataAnalyzer agent
|
|
67
|
+
console.log("\n📋 Test 3: Full analysis using DataAnalyzer agent!!!!")
|
|
68
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
69
|
+
|
|
70
|
+
const analysisResult =
|
|
71
|
+
await send peers.event("analyze").role(DataScientist).any()({
|
|
72
|
+
numbers: [15, 25, 35, 45, 55, 65, 75]
|
|
73
|
+
}) timeout 10s
|
|
74
|
+
|
|
75
|
+
console.log("Result:", JSON.stringify(analysisResult, null, 2))
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
tests_completed: 3
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
run DemoRunner.runTest({})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Hello World with Claude
|
|
3
|
+
// Using Anthropic's Claude instead of OpenAI
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.helloworld.claude"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
|
|
10
|
+
// Agent with playbook using Claude
|
|
11
|
+
Agent Greeter : Worker {
|
|
12
|
+
llm default = { provider: "anthropic", model: "claude-3-5-haiku-20241022", temperature: 0.7, max_tokens: 200 }
|
|
13
|
+
|
|
14
|
+
on greet(args: Json) {
|
|
15
|
+
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.
|
|
26
|
+
"""
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
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" })
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Hello World with LLM Playbook
|
|
3
|
+
// Simple example showing playbook execution with real LLM
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.helloworld"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
|
|
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 }
|
|
13
|
+
|
|
14
|
+
on greet(args: Json) {
|
|
15
|
+
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.
|
|
26
|
+
"""
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
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" })
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Minimal test
|
|
2
|
+
package "test"
|
|
3
|
+
|
|
4
|
+
role Worker { can execute }
|
|
5
|
+
|
|
6
|
+
Agent Test : Worker {
|
|
7
|
+
on test(args: Json) {
|
|
8
|
+
return { ok: true }
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
Team T {
|
|
13
|
+
t = Test
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
Agent Orch : Worker {
|
|
17
|
+
uses Team T
|
|
18
|
+
on start(args: Json) {
|
|
19
|
+
const r = await send peers.event("test").role(Worker).any()({}) timeout 2s
|
|
20
|
+
return r
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
run Orch.start({})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — MCP (Model Context Protocol) Example
|
|
3
|
+
// Demonstrates using MCP addresses to reference remote agents
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.mcp"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
role Lead { can delegate }
|
|
10
|
+
|
|
11
|
+
// Local agent
|
|
12
|
+
Agent LocalProcessor : Worker {
|
|
13
|
+
on process(args: Json) {
|
|
14
|
+
const data = args.data
|
|
15
|
+
const processed = "LOCAL: " + data
|
|
16
|
+
return { result: processed, source: "local" }
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Team with both local and remote (MCP) agents
|
|
21
|
+
Team HybridTeam {
|
|
22
|
+
// Regular local agent
|
|
23
|
+
local = LocalProcessor
|
|
24
|
+
|
|
25
|
+
// Remote agents via MCP addresses
|
|
26
|
+
// Format: mcp://server/path
|
|
27
|
+
remote1 = mcp://agent.local/processor
|
|
28
|
+
remote2 = mcp://service.local/analyzer
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Orchestrator that uses both local and remote agents
|
|
32
|
+
Agent Orchestrator : Lead {
|
|
33
|
+
uses Team HybridTeam
|
|
34
|
+
|
|
35
|
+
on start(args: Json) {
|
|
36
|
+
const data = args.data
|
|
37
|
+
|
|
38
|
+
// This will try local first, then MCP agents
|
|
39
|
+
const result =
|
|
40
|
+
await send peers.event("process").role(Worker).any()({ data: data }) timeout 10s
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
success: true,
|
|
44
|
+
result: result
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
on processAll(args: Json) {
|
|
49
|
+
const data = args.data
|
|
50
|
+
|
|
51
|
+
// Process with ALL agents (local + MCP)
|
|
52
|
+
const results =
|
|
53
|
+
await send peers.event("process").role(Worker).all()({ data: data }) timeout 15s
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
count: 3,
|
|
58
|
+
results: results
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Example with MCP skill reference
|
|
64
|
+
Team DistributedTeam {
|
|
65
|
+
orchestrator = Orchestrator
|
|
66
|
+
// Reference a remote skill
|
|
67
|
+
sentiment = mcp://skills.local/sentiment-analysis
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
run Orchestrator.start({ data: "Hello from Koi with MCP support!" })
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
package "demo.multi.event"
|
|
2
|
+
|
|
3
|
+
role Calculator { can calculate }
|
|
4
|
+
role Coordinator { can coordinate }
|
|
5
|
+
|
|
6
|
+
// Agent con múltiples event handlers
|
|
7
|
+
// Cada handler tiene su propio affordance (del playbook)
|
|
8
|
+
Agent StatisticsCalculator : Calculator {
|
|
9
|
+
llm default = {
|
|
10
|
+
provider: "openai",
|
|
11
|
+
model: "gpt-4o-mini",
|
|
12
|
+
temperature: 0.1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Event handler para calcular media
|
|
16
|
+
on mean(args: Json) {
|
|
17
|
+
playbook """
|
|
18
|
+
Calculate the arithmetic mean (average) of the numbers: ${JSON.stringify(args.numbers)}
|
|
19
|
+
|
|
20
|
+
Sum all numbers and divide by the count.
|
|
21
|
+
IMPORTANT: Actually perform the calculation and return ONLY: { "operation": "mean", "result": <numeric_value> }
|
|
22
|
+
"""
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Event handler para calcular mediana
|
|
26
|
+
on median(args: Json) {
|
|
27
|
+
playbook """
|
|
28
|
+
Calculate the median (middle value) of ${JSON.stringify(args.numbers)}
|
|
29
|
+
|
|
30
|
+
Sort numbers, find middle. If even count, average two middle values.
|
|
31
|
+
Return: { "operation": "median", "result": <numeric_value> }
|
|
32
|
+
"""
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Event handler para calcular desviación estándar
|
|
36
|
+
on stddev(args: Json) {
|
|
37
|
+
playbook """
|
|
38
|
+
Calculate the standard deviation for ${JSON.stringify(args.numbers)}
|
|
39
|
+
|
|
40
|
+
DO NOT return a plan. Perform the actual calculation and return only the result.
|
|
41
|
+
Formula: sqrt(sum((x - mean)²) / n)
|
|
42
|
+
Return ONLY: { "operation": "stddev", "result": <numeric_result> }
|
|
43
|
+
"""
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Team CalculatorTeam {
|
|
48
|
+
calculator = StatisticsCalculator
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Orchestrator que decide qué evento enviar basándose en la intención
|
|
52
|
+
Agent Orchestrator : Coordinator {
|
|
53
|
+
llm default = {
|
|
54
|
+
provider: "openai",
|
|
55
|
+
model: "gpt-4o-mini",
|
|
56
|
+
temperature: 0.1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
uses Team CalculatorTeam
|
|
60
|
+
|
|
61
|
+
on process(args: Json) {
|
|
62
|
+
playbook """
|
|
63
|
+
Process this statistical request: ${JSON.stringify(args)}
|
|
64
|
+
|
|
65
|
+
You have access to Calculator agents with these event handlers:
|
|
66
|
+
- "mean" event: Calculate arithmetic mean/average
|
|
67
|
+
- "median" event: Calculate median (middle value)
|
|
68
|
+
- "stddev" event: Calculate standard deviation (measure of spread)
|
|
69
|
+
|
|
70
|
+
Based on the user's request description in "operation", determine which statistical calculation is needed.
|
|
71
|
+
Then delegate by returning an action:
|
|
72
|
+
|
|
73
|
+
{
|
|
74
|
+
"actions": [
|
|
75
|
+
{
|
|
76
|
+
"title": "Calculating <operation>",
|
|
77
|
+
"intent": "<choose: calculate mean | calculate median | calculate standard deviation>",
|
|
78
|
+
"data": { "numbers": ${JSON.stringify(args.numbers)} }
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
The system will route to the appropriate event handler based on the intent.
|
|
84
|
+
"""
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Team OrchestratorTeam {
|
|
89
|
+
orchestrator = Orchestrator
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Agent Main : Coordinator {
|
|
93
|
+
uses Team OrchestratorTeam
|
|
94
|
+
|
|
95
|
+
on start(args: Json) {
|
|
96
|
+
console.log("╔════════════════════════════════════════════╗")
|
|
97
|
+
console.log("║ Multi Event Handler Test ║")
|
|
98
|
+
console.log("║ Semantic routing to event handlers ║")
|
|
99
|
+
console.log("╚════════════════════════════════════════════╝\n")
|
|
100
|
+
|
|
101
|
+
// Test 1: Request mean calculation
|
|
102
|
+
console.log("📋 Test 1: Calculate average of numbers")
|
|
103
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
104
|
+
|
|
105
|
+
const meanResult =
|
|
106
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
107
|
+
operation: "calculate the average",
|
|
108
|
+
numbers: [10, 20, 30, 40, 50]
|
|
109
|
+
}) timeout 30s
|
|
110
|
+
|
|
111
|
+
console.log("Result:", JSON.stringify(meanResult, null, 2))
|
|
112
|
+
|
|
113
|
+
// Test 2: Request median calculation
|
|
114
|
+
console.log("\n📋 Test 2: Find the middle value")
|
|
115
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
116
|
+
|
|
117
|
+
const medianResult =
|
|
118
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
119
|
+
operation: "find the middle value",
|
|
120
|
+
numbers: [1, 3, 5, 7, 9, 11]
|
|
121
|
+
}) timeout 30s
|
|
122
|
+
|
|
123
|
+
console.log("Result:", JSON.stringify(medianResult, null, 2))
|
|
124
|
+
|
|
125
|
+
// Test 3: Request standard deviation
|
|
126
|
+
console.log("\n📋 Test 3: Calculate spread of data")
|
|
127
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
128
|
+
|
|
129
|
+
const stddevResult =
|
|
130
|
+
await send peers.event("process").role(Coordinator).any()({
|
|
131
|
+
operation: "measure how spread out the numbers are",
|
|
132
|
+
numbers: [10, 20, 30, 40, 50]
|
|
133
|
+
}) timeout 30s
|
|
134
|
+
|
|
135
|
+
console.log("Result:", JSON.stringify(stddevResult, null, 2))
|
|
136
|
+
|
|
137
|
+
return {
|
|
138
|
+
success: true,
|
|
139
|
+
tests_completed: 3
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
run Main.start({})
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// New Import System Test
|
|
3
|
+
// Tests the new simplified import syntax
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.new.import"
|
|
7
|
+
|
|
8
|
+
// New import syntax - imports everything (Skills, Agents, Roles, Teams)
|
|
9
|
+
import "./skills/math-operations.koi"
|
|
10
|
+
import "@koi-lang/common-skills"
|
|
11
|
+
|
|
12
|
+
role Worker { can work }
|
|
13
|
+
|
|
14
|
+
// Agent that uses imported skills from both local and npm package
|
|
15
|
+
Agent DataProcessor : Worker {
|
|
16
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 300 }
|
|
17
|
+
// Comma-separated syntax (cleaner!)
|
|
18
|
+
uses Skill MathOperations, DataValidation, DataTransformation
|
|
19
|
+
|
|
20
|
+
on process(args: Json) {
|
|
21
|
+
playbook """
|
|
22
|
+
Process the request: ${JSON.stringify(args)}
|
|
23
|
+
|
|
24
|
+
Use the available tools (math, validation, transformation) to complete the task.
|
|
25
|
+
Return the result as JSON.
|
|
26
|
+
"""
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Team WorkerTeam {
|
|
31
|
+
processor = DataProcessor
|
|
32
|
+
// Also use the imported EmailValidator agent
|
|
33
|
+
emailValidator = EmailValidator
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Demo runner
|
|
37
|
+
Agent DemoRunner : Worker {
|
|
38
|
+
uses Team WorkerTeam
|
|
39
|
+
|
|
40
|
+
on runTest(args: Json) {
|
|
41
|
+
console.log("╔════════════════════════════════════════════╗")
|
|
42
|
+
console.log("║ New Import System Test ║")
|
|
43
|
+
console.log("║ Local files + npm packages ║")
|
|
44
|
+
console.log("╚════════════════════════════════════════════╝\n")
|
|
45
|
+
|
|
46
|
+
// Test 1: Use local skill (math)
|
|
47
|
+
console.log("📋 Test 1: Math operation from local skill")
|
|
48
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
49
|
+
|
|
50
|
+
const mathResult =
|
|
51
|
+
await send peers.event("process").role(Worker).any()({
|
|
52
|
+
operation: "add",
|
|
53
|
+
a: 15,
|
|
54
|
+
b: 27
|
|
55
|
+
}) timeout 10s
|
|
56
|
+
|
|
57
|
+
console.log("Result:", JSON.stringify(mathResult, null, 2))
|
|
58
|
+
|
|
59
|
+
// Test 2: Use npm package skill (validation)
|
|
60
|
+
console.log("\n📋 Test 2: Email validation from npm package")
|
|
61
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
62
|
+
|
|
63
|
+
const validationResult =
|
|
64
|
+
await send peers.event("process").role(Worker).any()({
|
|
65
|
+
operation: "validateEmail",
|
|
66
|
+
email: "test@example.com"
|
|
67
|
+
}) timeout 10s
|
|
68
|
+
|
|
69
|
+
console.log("Result:", JSON.stringify(validationResult, null, 2))
|
|
70
|
+
|
|
71
|
+
// Test 3: Use imported agent directly
|
|
72
|
+
console.log("\n📋 Test 3: Using imported EmailValidator agent")
|
|
73
|
+
console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
74
|
+
|
|
75
|
+
const agentResult =
|
|
76
|
+
await send peers.event("validate").role(Validator).any()({
|
|
77
|
+
email: "invalid-email"
|
|
78
|
+
}) timeout 10s
|
|
79
|
+
|
|
80
|
+
console.log("Result:", JSON.stringify(agentResult, null, 2))
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
success: true,
|
|
84
|
+
tests_completed: 3
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
run DemoRunner.runTest({})
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Koi — Data Pipeline Example
|
|
3
|
+
// Shows multi-stage data processing
|
|
4
|
+
// ============================================================
|
|
5
|
+
|
|
6
|
+
package "demo.koi.pipeline"
|
|
7
|
+
|
|
8
|
+
role Worker { can execute }
|
|
9
|
+
role Reviewer { can critique }
|
|
10
|
+
role Lead { can delegate }
|
|
11
|
+
|
|
12
|
+
Agent Extractor : Worker {
|
|
13
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.3, max_tokens: 300 }
|
|
14
|
+
|
|
15
|
+
on extract(args: Json) {
|
|
16
|
+
playbook """
|
|
17
|
+
You are a data extraction specialist. Extract and structure the raw input data from args.raw.
|
|
18
|
+
|
|
19
|
+
Your task:
|
|
20
|
+
1. Parse the raw input text
|
|
21
|
+
2. Identify key information (content, metadata, timestamp)
|
|
22
|
+
3. Calculate the text length
|
|
23
|
+
4. Structure it into a clean data object
|
|
24
|
+
|
|
25
|
+
Return ONLY this exact JSON structure (no markdown, no explanations):
|
|
26
|
+
{
|
|
27
|
+
"extracted": true,
|
|
28
|
+
"data": {
|
|
29
|
+
"text": "the raw text content",
|
|
30
|
+
"length": 42,
|
|
31
|
+
"timestamp": "2026-01-21"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
Use the current date for timestamp. Be precise and thorough.
|
|
36
|
+
"""
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Agent Transformer : Worker {
|
|
41
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.3, max_tokens: 300 }
|
|
42
|
+
|
|
43
|
+
on transform(args: Json) {
|
|
44
|
+
playbook """
|
|
45
|
+
You are a data transformation specialist. Transform the extracted data from args.data into an enriched format.
|
|
46
|
+
|
|
47
|
+
Your task:
|
|
48
|
+
1. Take the extracted data (text, length, timestamp)
|
|
49
|
+
2. Apply business rules and enrichments
|
|
50
|
+
3. Add a "processed_at" field with the timestamp
|
|
51
|
+
4. Mark the data as enriched
|
|
52
|
+
|
|
53
|
+
Return ONLY this exact JSON structure (no markdown, no explanations):
|
|
54
|
+
{
|
|
55
|
+
"transformed": true,
|
|
56
|
+
"data": {
|
|
57
|
+
"text": "the original text",
|
|
58
|
+
"length": 42,
|
|
59
|
+
"enriched": true,
|
|
60
|
+
"processed_at": "timestamp from args.data"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
Preserve all original data fields while adding enrichment.
|
|
65
|
+
"""
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Agent Validator : Reviewer {
|
|
70
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 200 }
|
|
71
|
+
|
|
72
|
+
on validate(args: Json) {
|
|
73
|
+
playbook """
|
|
74
|
+
You are a data quality validator. Validate that the transformed data in args.data meets quality requirements.
|
|
75
|
+
|
|
76
|
+
Your validation rules:
|
|
77
|
+
1. Check that "enriched" field is true
|
|
78
|
+
2. Ensure all required fields are present (text, length, enriched, processed_at)
|
|
79
|
+
3. Verify data types are correct
|
|
80
|
+
4. Check that text is not empty and length is positive
|
|
81
|
+
|
|
82
|
+
Return ONLY this exact JSON structure (no markdown, no explanations):
|
|
83
|
+
{
|
|
84
|
+
"valid": true,
|
|
85
|
+
"message": "Data passes validation"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
OR if validation fails:
|
|
89
|
+
{
|
|
90
|
+
"valid": false,
|
|
91
|
+
"message": "Specific reason for failure"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
Be strict but fair in validation.
|
|
95
|
+
"""
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Agent Loader : Worker {
|
|
100
|
+
llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.2, max_tokens: 250 }
|
|
101
|
+
|
|
102
|
+
on load(args: Json) {
|
|
103
|
+
playbook """
|
|
104
|
+
You are a data loading specialist. Load the validated data from args.data into the final destination.
|
|
105
|
+
|
|
106
|
+
Your task:
|
|
107
|
+
1. Take the validated data
|
|
108
|
+
2. Prepare it for storage in the database
|
|
109
|
+
3. Return metadata about the load operation
|
|
110
|
+
4. Include the full data in the response
|
|
111
|
+
|
|
112
|
+
Return ONLY this exact JSON structure (no markdown, no explanations):
|
|
113
|
+
{
|
|
114
|
+
"loaded": true,
|
|
115
|
+
"records": 1,
|
|
116
|
+
"destination": "database",
|
|
117
|
+
"data": { ...the full data from args.data... }
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
Confirm successful loading with appropriate metadata.
|
|
121
|
+
"""
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
Team Pipeline {
|
|
126
|
+
extractor = Extractor
|
|
127
|
+
transformer = Transformer
|
|
128
|
+
validator = Validator
|
|
129
|
+
loader = Loader
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
Agent Orchestrator : Lead {
|
|
133
|
+
uses Team Pipeline
|
|
134
|
+
|
|
135
|
+
on start(args: Json) {
|
|
136
|
+
const raw = args.input
|
|
137
|
+
|
|
138
|
+
const extracted =
|
|
139
|
+
await send peers.event("extract").role(Worker).any()({ raw: raw }) timeout 5s
|
|
140
|
+
|
|
141
|
+
const transformed =
|
|
142
|
+
await send peers.event("transform").role(Worker).any()({ data: extracted.data }) timeout 5s
|
|
143
|
+
|
|
144
|
+
const validation =
|
|
145
|
+
await send peers.event("validate").role(Reviewer).any()({ data: transformed.data }) timeout 5s
|
|
146
|
+
|
|
147
|
+
if validation.valid == false {
|
|
148
|
+
return { ok: false, error: validation.message }
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const loaded =
|
|
152
|
+
await send peers.event("load").role(Worker).any()({ data: transformed.data }) timeout 5s
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
ok: true,
|
|
156
|
+
pipeline: "complete",
|
|
157
|
+
result: loaded
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
run Orchestrator.start({ input: "Sample data to process through pipeline" })
|