@koi-language/koi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/QUICKSTART.md +89 -0
  2. package/README.md +545 -0
  3. package/examples/actions-demo.koi +177 -0
  4. package/examples/cache-test.koi +29 -0
  5. package/examples/calculator.koi +61 -0
  6. package/examples/clear-registry.js +33 -0
  7. package/examples/clear-registry.koi +30 -0
  8. package/examples/code-introspection-test.koi +149 -0
  9. package/examples/counter.koi +132 -0
  10. package/examples/delegation-test.koi +52 -0
  11. package/examples/directory-import-test.koi +84 -0
  12. package/examples/hello-world-claude.koi +52 -0
  13. package/examples/hello-world.koi +52 -0
  14. package/examples/hello.koi +24 -0
  15. package/examples/mcp-example.koi +70 -0
  16. package/examples/multi-event-handler-test.koi +144 -0
  17. package/examples/new-import-test.koi +89 -0
  18. package/examples/pipeline.koi +162 -0
  19. package/examples/registry-demo.koi +184 -0
  20. package/examples/registry-playbook-demo.koi +162 -0
  21. package/examples/registry-playbook-email-compositor-2.koi +140 -0
  22. package/examples/registry-playbook-email-compositor.koi +140 -0
  23. package/examples/sentiment.koi +90 -0
  24. package/examples/simple.koi +48 -0
  25. package/examples/skill-import-test.koi +76 -0
  26. package/examples/skills/advanced/index.koi +95 -0
  27. package/examples/skills/math-operations.koi +69 -0
  28. package/examples/skills/string-operations.koi +56 -0
  29. package/examples/task-chaining-demo.koi +244 -0
  30. package/examples/test-await.koi +22 -0
  31. package/examples/test-crypto-sha256.koi +196 -0
  32. package/examples/test-delegation.koi +41 -0
  33. package/examples/test-multi-team-routing.koi +258 -0
  34. package/examples/test-no-handler.koi +35 -0
  35. package/examples/test-npm-import.koi +67 -0
  36. package/examples/test-parse.koi +10 -0
  37. package/examples/test-peers-with-team.koi +59 -0
  38. package/examples/test-permissions-fail.koi +20 -0
  39. package/examples/test-permissions.koi +36 -0
  40. package/examples/test-simple-registry.koi +31 -0
  41. package/examples/test-typescript-import.koi +64 -0
  42. package/examples/test-uses-team-syntax.koi +25 -0
  43. package/examples/test-uses-team.koi +31 -0
  44. package/examples/utils/calculator.test.ts +144 -0
  45. package/examples/utils/calculator.ts +56 -0
  46. package/examples/utils/math-helpers.js +50 -0
  47. package/examples/utils/math-helpers.ts +55 -0
  48. package/examples/web-delegation-demo.koi +165 -0
  49. package/package.json +78 -0
  50. package/src/cli/koi.js +793 -0
  51. package/src/compiler/build-optimizer.js +447 -0
  52. package/src/compiler/cache-manager.js +274 -0
  53. package/src/compiler/import-resolver.js +369 -0
  54. package/src/compiler/parser.js +7542 -0
  55. package/src/compiler/transpiler.js +1105 -0
  56. package/src/compiler/typescript-transpiler.js +148 -0
  57. package/src/grammar/koi.pegjs +767 -0
  58. package/src/runtime/action-registry.js +172 -0
  59. package/src/runtime/actions/call-skill.js +45 -0
  60. package/src/runtime/actions/format.js +115 -0
  61. package/src/runtime/actions/print.js +42 -0
  62. package/src/runtime/actions/registry-delete.js +37 -0
  63. package/src/runtime/actions/registry-get.js +37 -0
  64. package/src/runtime/actions/registry-keys.js +33 -0
  65. package/src/runtime/actions/registry-search.js +34 -0
  66. package/src/runtime/actions/registry-set.js +50 -0
  67. package/src/runtime/actions/return.js +31 -0
  68. package/src/runtime/actions/send-message.js +58 -0
  69. package/src/runtime/actions/update-state.js +36 -0
  70. package/src/runtime/agent.js +1368 -0
  71. package/src/runtime/cli-logger.js +205 -0
  72. package/src/runtime/incremental-json-parser.js +201 -0
  73. package/src/runtime/index.js +33 -0
  74. package/src/runtime/llm-provider.js +1372 -0
  75. package/src/runtime/mcp-client.js +1171 -0
  76. package/src/runtime/planner.js +273 -0
  77. package/src/runtime/registry-backends/keyv-sqlite.js +215 -0
  78. package/src/runtime/registry-backends/local.js +260 -0
  79. package/src/runtime/registry.js +162 -0
  80. package/src/runtime/role.js +14 -0
  81. package/src/runtime/router.js +395 -0
  82. package/src/runtime/runtime.js +113 -0
  83. package/src/runtime/skill-selector.js +173 -0
  84. package/src/runtime/skill.js +25 -0
  85. package/src/runtime/team.js +162 -0
@@ -0,0 +1,20 @@
1
+ // Test that permissions are enforced
2
+ package "test.permissions.fail"
3
+
4
+ // Role without execute permission
5
+ role ReadOnly { can registry_read }
6
+
7
+ // Agent without execute permission - should fail when trying to print
8
+ Agent ReadOnlyAgent : ReadOnly {
9
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
10
+
11
+ on test(args: Json) {
12
+ playbook """
13
+ Try to print a message (should fail due to missing execute permission).
14
+
15
+ Show: "❌ This should not appear because print requires execute permission"
16
+ """
17
+ }
18
+ }
19
+
20
+ run ReadOnlyAgent.test({})
@@ -0,0 +1,36 @@
1
+ // Test permissions system
2
+ package "test.permissions"
3
+
4
+ // Role with execute permission
5
+ role Worker { can execute }
6
+
7
+ // Role without execute permission (empty)
8
+ role ReadOnly { can registry_read }
9
+
10
+ // Agent with execute permission - should work
11
+ Agent TestAgent : Worker {
12
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
13
+
14
+ on test(args: Json) {
15
+ playbook """
16
+ Print a simple message to test permissions.
17
+
18
+ Show: "✅ Print action works with execute permission"
19
+ """
20
+ }
21
+ }
22
+
23
+ // Agent without execute permission - should fail
24
+ Agent ReadOnlyAgent : ReadOnly {
25
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
26
+
27
+ on test(args: Json) {
28
+ playbook """
29
+ Try to print a message (should fail due to missing execute permission).
30
+
31
+ Show: "❌ This should not appear"
32
+ """
33
+ }
34
+ }
35
+
36
+ run TestAgent.test({})
@@ -0,0 +1,31 @@
1
+ // Simple test for registry operations
2
+ package "test.simple"
3
+
4
+ role Worker { can execute }
5
+
6
+ Agent SimpleWorker : Worker {
7
+ llm default = { provider: "openai", model: "gpt-4o-mini" }
8
+
9
+ on saveUser(args: Json) {
10
+ playbook """
11
+ Save a user to the registry with key "user:${args.id}" and value:
12
+ {
13
+ "name": "${args.name}",
14
+ "age": ${args.age},
15
+ "createdAt": "${Date.now()}"
16
+ }
17
+
18
+ Return: { "success": true, "message": "User saved" }
19
+ """
20
+ }
21
+
22
+ on getUser(args: Json) {
23
+ playbook """
24
+ Get the user from registry with key "user:${args.id}".
25
+ If found, return: { "found": true, "user": [the complete user object] }
26
+ If not found, return: { "found": false }
27
+ """
28
+ }
29
+ }
30
+
31
+ run SimpleWorker.saveUser({ id: "test1", name: "TestUser", age: 25 })
@@ -0,0 +1,64 @@
1
+ package "test.typescript.import"
2
+
3
+ // Import TypeScript module
4
+ import "./utils/math-helpers.ts"
5
+
6
+ role Worker { can work }
7
+
8
+ Agent MathAgent : Worker {
9
+ on calculate(args: Json) {
10
+ console.log("=".repeat(60))
11
+ console.log("Testing TypeScript Import")
12
+ console.log("=".repeat(60))
13
+
14
+ // Test simple functions
15
+ const sum = utils_math_helpers.add(5, 3)
16
+ console.log("\nTest 1: add(5, 3) =", sum)
17
+
18
+ const product = utils_math_helpers.multiply(4, 7)
19
+ console.log("Test 2: multiply(4, 7) =", product)
20
+
21
+ const fib10 = utils_math_helpers.fibonacci(10)
22
+ console.log("Test 3: fibonacci(10) =", fib10)
23
+
24
+ const is17Prime = utils_math_helpers.isPrime(17)
25
+ console.log("Test 4: isPrime(17) =", is17Prime)
26
+
27
+ // Test constants
28
+ console.log("\nTest 5: PI =", utils_math_helpers.PI)
29
+ console.log("Test 6: E =", utils_math_helpers.E)
30
+
31
+ // Test class instantiation
32
+ const calc = new utils_math_helpers.Calculator()
33
+ const r1 = calc.add(10, 20)
34
+ const r2 = calc.subtract(50, 15)
35
+ console.log("\nTest 7: Calculator.add(10, 20) =", r1)
36
+ console.log("Test 8: Calculator.subtract(50, 15) =", r2)
37
+
38
+ const history = calc.getHistory()
39
+ console.log("Test 9: Calculator history:", JSON.stringify(history))
40
+
41
+ console.log("\n" + "=".repeat(60))
42
+ console.log("All tests completed!")
43
+ console.log("=".repeat(60))
44
+
45
+ return {
46
+ success: true,
47
+ tests: {
48
+ add: sum,
49
+ multiply: product,
50
+ fibonacci: fib10,
51
+ isPrime: is17Prime,
52
+ pi: utils_math_helpers.PI,
53
+ e: utils_math_helpers.E,
54
+ calculator: {
55
+ add: r1,
56
+ subtract: r2,
57
+ history: history
58
+ }
59
+ }
60
+ }
61
+ }
62
+ }
63
+
64
+ run MathAgent.calculate({})
@@ -0,0 +1,25 @@
1
+ package "test.uses.team"
2
+
3
+ role Worker { can work }
4
+
5
+ Agent TestAgent : Worker {
6
+ on work(args: Json) {
7
+ return { result: "working" }
8
+ }
9
+ }
10
+
11
+ Team TestTeam {
12
+ worker = TestAgent
13
+ }
14
+
15
+ Agent MainAgent : Worker {
16
+ // Esta sintaxis SÍ debe funcionar
17
+ uses Team TestTeam
18
+
19
+ on start(args: Json) {
20
+ const result = await send peers.event("work").role(Worker).any()({}) timeout 5s
21
+ return result
22
+ }
23
+ }
24
+
25
+ run MainAgent.start({})
@@ -0,0 +1,31 @@
1
+ package "test.uses.team"
2
+
3
+ role Worker { can execute }
4
+ role Manager { can manage }
5
+
6
+ Agent SimpleWorker : Worker {
7
+ on doWork(args: Json) {
8
+ playbook """
9
+ Do some work: ${args.task}
10
+ Return JSON: { "result": "work done" }
11
+ """
12
+ }
13
+ }
14
+
15
+ Team SimpleTeam {
16
+ worker = SimpleWorker
17
+ }
18
+
19
+ Agent TeamUser : Manager {
20
+ uses Team SimpleTeam
21
+
22
+ on requestWork(args: Json) {
23
+ playbook """
24
+ Request work from team: ${args.request}
25
+ Return JSON with actions:
26
+ { "actions": [{ "intent": "do work", "data": { "task": "${args.request}" } }] }
27
+ """
28
+ }
29
+ }
30
+
31
+ run TeamUser.requestWork({ request: "process data" })
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Unit tests for Calculator module using Jest
3
+ */
4
+
5
+ import { Calculator, factorial, isPrime } from './calculator';
6
+
7
+ describe('Calculator', () => {
8
+ let calc: Calculator;
9
+
10
+ beforeEach(() => {
11
+ calc = new Calculator();
12
+ });
13
+
14
+ describe('add', () => {
15
+ test('should add two positive numbers', () => {
16
+ expect(calc.add(2, 3)).toBe(5);
17
+ });
18
+
19
+ test('should add negative numbers', () => {
20
+ expect(calc.add(-5, -3)).toBe(-8);
21
+ });
22
+
23
+ test('should add zero', () => {
24
+ expect(calc.add(5, 0)).toBe(5);
25
+ });
26
+ });
27
+
28
+ describe('subtract', () => {
29
+ test('should subtract two numbers', () => {
30
+ expect(calc.subtract(10, 4)).toBe(6);
31
+ });
32
+
33
+ test('should handle negative results', () => {
34
+ expect(calc.subtract(5, 10)).toBe(-5);
35
+ });
36
+ });
37
+
38
+ describe('multiply', () => {
39
+ test('should multiply two numbers', () => {
40
+ expect(calc.multiply(4, 5)).toBe(20);
41
+ });
42
+
43
+ test('should return zero when multiplying by zero', () => {
44
+ expect(calc.multiply(100, 0)).toBe(0);
45
+ });
46
+
47
+ test('should handle negative numbers', () => {
48
+ expect(calc.multiply(-3, 4)).toBe(-12);
49
+ });
50
+ });
51
+
52
+ describe('divide', () => {
53
+ test('should divide two numbers', () => {
54
+ expect(calc.divide(10, 2)).toBe(5);
55
+ });
56
+
57
+ test('should handle decimal results', () => {
58
+ expect(calc.divide(7, 2)).toBe(3.5);
59
+ });
60
+
61
+ test('should throw error on division by zero', () => {
62
+ expect(() => calc.divide(10, 0)).toThrow('Division by zero');
63
+ });
64
+ });
65
+
66
+ describe('power', () => {
67
+ test('should calculate power correctly', () => {
68
+ expect(calc.power(2, 3)).toBe(8);
69
+ });
70
+
71
+ test('should handle exponent of zero', () => {
72
+ expect(calc.power(5, 0)).toBe(1);
73
+ });
74
+
75
+ test('should handle negative exponents', () => {
76
+ expect(calc.power(2, -2)).toBe(0.25);
77
+ });
78
+ });
79
+
80
+ describe('percentage', () => {
81
+ test('should calculate percentage correctly', () => {
82
+ expect(calc.percentage(100, 10)).toBe(10);
83
+ });
84
+
85
+ test('should handle decimal percentages', () => {
86
+ expect(calc.percentage(200, 2.5)).toBe(5);
87
+ });
88
+ });
89
+ });
90
+
91
+ describe('factorial', () => {
92
+ test('should calculate factorial of 0', () => {
93
+ expect(factorial(0)).toBe(1);
94
+ });
95
+
96
+ test('should calculate factorial of 1', () => {
97
+ expect(factorial(1)).toBe(1);
98
+ });
99
+
100
+ test('should calculate factorial of 5', () => {
101
+ expect(factorial(5)).toBe(120);
102
+ });
103
+
104
+ test('should calculate factorial of 10', () => {
105
+ expect(factorial(10)).toBe(3628800);
106
+ });
107
+
108
+ test('should throw error for negative numbers', () => {
109
+ expect(() => factorial(-1)).toThrow('Factorial is not defined for negative numbers');
110
+ });
111
+ });
112
+
113
+ describe('isPrime', () => {
114
+ test('should return false for numbers less than 2', () => {
115
+ expect(isPrime(0)).toBe(false);
116
+ expect(isPrime(1)).toBe(false);
117
+ expect(isPrime(-5)).toBe(false);
118
+ });
119
+
120
+ test('should return true for prime numbers', () => {
121
+ expect(isPrime(2)).toBe(true);
122
+ expect(isPrime(3)).toBe(true);
123
+ expect(isPrime(5)).toBe(true);
124
+ expect(isPrime(7)).toBe(true);
125
+ expect(isPrime(11)).toBe(true);
126
+ expect(isPrime(17)).toBe(true);
127
+ expect(isPrime(19)).toBe(true);
128
+ });
129
+
130
+ test('should return false for composite numbers', () => {
131
+ expect(isPrime(4)).toBe(false);
132
+ expect(isPrime(6)).toBe(false);
133
+ expect(isPrime(8)).toBe(false);
134
+ expect(isPrime(9)).toBe(false);
135
+ expect(isPrime(10)).toBe(false);
136
+ expect(isPrime(15)).toBe(false);
137
+ expect(isPrime(21)).toBe(false);
138
+ });
139
+
140
+ test('should handle large primes', () => {
141
+ expect(isPrime(97)).toBe(true);
142
+ expect(isPrime(100)).toBe(false);
143
+ });
144
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Calculator module to demonstrate unit testing in Koi
3
+ */
4
+
5
+ export class Calculator {
6
+ add(a: number, b: number): number {
7
+ return a + b;
8
+ }
9
+
10
+ subtract(a: number, b: number): number {
11
+ return a - b;
12
+ }
13
+
14
+ multiply(a: number, b: number): number {
15
+ return a * b;
16
+ }
17
+
18
+ divide(a: number, b: number): number {
19
+ if (b === 0) {
20
+ throw new Error('Division by zero');
21
+ }
22
+ return a / b;
23
+ }
24
+
25
+ power(base: number, exponent: number): number {
26
+ return Math.pow(base, exponent);
27
+ }
28
+
29
+ percentage(value: number, percent: number): number {
30
+ return (value * percent) / 100;
31
+ }
32
+ }
33
+
34
+ export function factorial(n: number): number {
35
+ if (n < 0) {
36
+ throw new Error('Factorial is not defined for negative numbers');
37
+ }
38
+ if (n === 0 || n === 1) {
39
+ return 1;
40
+ }
41
+ return n * factorial(n - 1);
42
+ }
43
+
44
+ export function isPrime(n: number): boolean {
45
+ if (n <= 1) return false;
46
+ if (n <= 3) return true;
47
+ if (n % 2 === 0 || n % 3 === 0) return false;
48
+
49
+ for (let i = 5; i * i <= n; i += 6) {
50
+ if (n % i === 0 || n % (i + 2) === 0) {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ return true;
56
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Math helper utilities (TypeScript module)
3
+ */
4
+ export function add(a, b) {
5
+ return a + b;
6
+ }
7
+ export function multiply(a, b) {
8
+ return a * b;
9
+ }
10
+ export function fibonacci(n) {
11
+ if (n <= 1)
12
+ return n;
13
+ return fibonacci(n - 1) + fibonacci(n - 2);
14
+ }
15
+ export function isPrime(n) {
16
+ if (n <= 1)
17
+ return false;
18
+ if (n <= 3)
19
+ return true;
20
+ if (n % 2 === 0 || n % 3 === 0)
21
+ return false;
22
+ for (let i = 5; i * i <= n; i += 6) {
23
+ if (n % i === 0 || n % (i + 2) === 0)
24
+ return false;
25
+ }
26
+ return true;
27
+ }
28
+ export class Calculator {
29
+ constructor() {
30
+ this.history = [];
31
+ }
32
+ add(a, b) {
33
+ const result = a + b;
34
+ this.history.push(`${a} + ${b} = ${result}`);
35
+ return result;
36
+ }
37
+ subtract(a, b) {
38
+ const result = a - b;
39
+ this.history.push(`${a} - ${b} = ${result}`);
40
+ return result;
41
+ }
42
+ getHistory() {
43
+ return [...this.history];
44
+ }
45
+ clearHistory() {
46
+ this.history = [];
47
+ }
48
+ }
49
+ export const PI = 3.141592653589793;
50
+ export const E = 2.718281828459045;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Math helper utilities (TypeScript module)
3
+ */
4
+
5
+ export function add(a: number, b: number): number {
6
+ return a + b;
7
+ }
8
+
9
+ export function multiply(a: number, b: number): number {
10
+ return a * b;
11
+ }
12
+
13
+ export function fibonacci(n: number): number {
14
+ if (n <= 1) return n;
15
+ return fibonacci(n - 1) + fibonacci(n - 2);
16
+ }
17
+
18
+ export function isPrime(n: number): boolean {
19
+ if (n <= 1) return false;
20
+ if (n <= 3) return true;
21
+ if (n % 2 === 0 || n % 3 === 0) return false;
22
+
23
+ for (let i = 5; i * i <= n; i += 6) {
24
+ if (n % i === 0 || n % (i + 2) === 0) return false;
25
+ }
26
+
27
+ return true;
28
+ }
29
+
30
+ export class Calculator {
31
+ private history: string[] = [];
32
+
33
+ add(a: number, b: number): number {
34
+ const result = a + b;
35
+ this.history.push(`${a} + ${b} = ${result}`);
36
+ return result;
37
+ }
38
+
39
+ subtract(a: number, b: number): number {
40
+ const result = a - b;
41
+ this.history.push(`${a} - ${b} = ${result}`);
42
+ return result;
43
+ }
44
+
45
+ getHistory(): string[] {
46
+ return [...this.history];
47
+ }
48
+
49
+ clearHistory(): void {
50
+ this.history = [];
51
+ }
52
+ }
53
+
54
+ export const PI = 3.141592653589793;
55
+ export const E = 2.718281828459045;
@@ -0,0 +1,165 @@
1
+ // ============================================================
2
+ // Web Delegation Demo
3
+ // Demonstrates delegation with indentation and loop detection
4
+ // ============================================================
5
+
6
+ package "demo.koi.delegation"
7
+
8
+ role Worker { can execute }
9
+ role Assistant { can help }
10
+
11
+ // ============================================================
12
+ // Skills - JavaScript functions agents can use
13
+ // ============================================================
14
+
15
+ Skill WebFetching {
16
+ affordance """
17
+ Fetch content from web URLs
18
+ """
19
+
20
+ export async function fetchUrl(args: any): Promise<any> {
21
+ const url = args.url;
22
+ console.log("[fetchUrl] Fetching: " + url);
23
+
24
+ try {
25
+ const response = await fetch(url, {
26
+ headers: {
27
+ "User-Agent": "Mozilla/5.0 (compatible; KoiBot/1.0)"
28
+ }
29
+ });
30
+
31
+ if (!response.ok) {
32
+ return {
33
+ url: url,
34
+ content: "Failed to fetch: " + response.status + " " + response.statusText,
35
+ status: "error",
36
+ error: true
37
+ };
38
+ }
39
+
40
+ const html = await response.text();
41
+ return {
42
+ url: url,
43
+ content: html,
44
+ status: "success",
45
+ length: html.length
46
+ };
47
+ } catch (error) {
48
+ console.error("[fetchUrl] Error:", error.message);
49
+ return {
50
+ url: url,
51
+ content: "Error fetching page: " + error.message,
52
+ status: "error",
53
+ error: true
54
+ };
55
+ }
56
+ }
57
+ }
58
+
59
+ // ============================================================
60
+ // Worker Agents with Specialized Capabilities
61
+ // ============================================================
62
+
63
+ Agent WebFetcher : Worker {
64
+ llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.2, max_tokens: 500 }
65
+ uses Skill WebFetching
66
+
67
+ on fetchWebPage(args: Json) {
68
+ playbook """
69
+ Download the web page from this URL: ${JSON.stringify(args.url)}
70
+
71
+ Use the available fetchUrl tool to download the content, then return the result.
72
+ """
73
+ }
74
+ }
75
+
76
+ Agent ContentSummarizer : Worker {
77
+ llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.3, max_tokens: 300 }
78
+
79
+ on summarize(args: Json) {
80
+ playbook """
81
+ Summarize the following content in 1-2 sentences:
82
+ ${JSON.stringify(args.content || args.text)}
83
+
84
+ Return your summary as JSON with a "summary" field containing the text.
85
+ """
86
+ }
87
+ }
88
+
89
+ Agent WordCounter : Worker {
90
+ llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.1, max_tokens: 200 }
91
+
92
+ on count(args: Json) {
93
+ playbook """
94
+ Count the number of words in this text: ${JSON.stringify(args.text || args.summary)}
95
+
96
+ Return JSON with "wordCount" field containing the number of words.
97
+ """
98
+ }
99
+ }
100
+
101
+ // ============================================================
102
+ // Orchestrator Agent
103
+ // ============================================================
104
+
105
+ Agent TaskOrchestrator : Assistant {
106
+ llm default = { provider: "openai", model: "gpt-4o-mini", temperature: 0.3, max_tokens: 800 }
107
+
108
+ //no cambies este agente!!! Es el que se encarga de delegar la tarea. No cambies su playbook!!!!
109
+ on processWebTask(args: Json) {
110
+ playbook """
111
+ User request: ${args.request}
112
+
113
+ You MUST execute the user request and return the result as JSON. Print also the plan you followed to execute the request.
114
+ """
115
+ }
116
+ }
117
+
118
+ // ============================================================
119
+ // Team
120
+ // ============================================================
121
+
122
+ Team WorkerTeam {
123
+ orchestrator = TaskOrchestrator
124
+ webFetcher = WebFetcher
125
+ summarizer = ContentSummarizer
126
+ counter = WordCounter
127
+ }
128
+
129
+ // ============================================================
130
+ // Demo Runner
131
+ // ============================================================
132
+
133
+ Agent DemoRunner : Assistant {
134
+ uses Team WorkerTeam
135
+
136
+ on runDemo(args: Json) {
137
+ console.log("╔════════════════════════════════════════════╗")
138
+ console.log("║ Web Delegation Demo ║")
139
+ console.log("║ Indented Delegation + Loop Detection ║")
140
+ console.log("╚════════════════════════════════════════════╝\n")
141
+
142
+ // ============================================================
143
+ // Test 1: Web → Summarize → Count (requires delegation)
144
+ // ============================================================
145
+ console.log("📋 Test 1: Fetch Web → Summarize → Count Words")
146
+ console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
147
+ console.log('Request: "Fetch web content, summarize it, then count the words in the summary"\n')
148
+
149
+ const test1 = await send peers.event("processWebTask").role(Assistant).any()({
150
+ request: "Fetch web content, summarize it, then count the words in the summary",
151
+ url: "https://soloprogramadores.com",
152
+ topic: "artificial intelligence"
153
+ }) timeout 60s
154
+
155
+ console.log("✅ Final Result:")
156
+ console.log(JSON.stringify(test1, null, 2))
157
+
158
+ return {
159
+ success: true,
160
+ tests_completed: 1
161
+ }
162
+ }
163
+ }
164
+
165
+ run DemoRunner.runDemo({})