@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,162 @@
|
|
|
1
|
+
import { mcpClient } from './mcp-client.js';
|
|
2
|
+
import { cliLogger } from './cli-logger.js';
|
|
3
|
+
|
|
4
|
+
export class Team {
|
|
5
|
+
constructor(name, members = {}) {
|
|
6
|
+
this.name = name;
|
|
7
|
+
this.members = members;
|
|
8
|
+
this._mcpResolved = new Map(); // Cache for resolved MCP addresses
|
|
9
|
+
|
|
10
|
+
// Automatically set this team as peers for all agent members
|
|
11
|
+
for (const memberName in members) {
|
|
12
|
+
const member = members[memberName];
|
|
13
|
+
// Check if it's an Agent instance (has handle method)
|
|
14
|
+
// Check if peers is not set or is the no-team proxy
|
|
15
|
+
const hasNoTeam = !member.peers || member.peers.__isNoTeamProxy;
|
|
16
|
+
|
|
17
|
+
if (member && typeof member.handle === 'function' && hasNoTeam) {
|
|
18
|
+
member.peers = this;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get(memberName) {
|
|
24
|
+
return this.members[memberName];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
event(eventName) {
|
|
28
|
+
return new TeamEventQuery(this, eventName);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
toString() {
|
|
32
|
+
return `Team(${this.name})`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class TeamEventQuery {
|
|
37
|
+
constructor(team, event) {
|
|
38
|
+
this.team = team;
|
|
39
|
+
this.eventName = event;
|
|
40
|
+
this.roleFilter = null;
|
|
41
|
+
this.selectionMode = null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
role(roleObj) {
|
|
45
|
+
this.roleFilter = roleObj;
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
any() {
|
|
50
|
+
this.selectionMode = 'any';
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
all() {
|
|
55
|
+
this.selectionMode = 'all';
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
isMCPAddress(value) {
|
|
60
|
+
if (typeof value === 'string' && value.startsWith('mcp://')) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (value && value.type === 'MCPAddress') {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async execute(args = {}) {
|
|
70
|
+
// Find matching agents
|
|
71
|
+
const candidates = [];
|
|
72
|
+
|
|
73
|
+
for (const [name, agentOrAddress] of Object.entries(this.team.members)) {
|
|
74
|
+
let agent = agentOrAddress;
|
|
75
|
+
|
|
76
|
+
// If it's an MCP address, resolve it
|
|
77
|
+
if (this.isMCPAddress(agentOrAddress)) {
|
|
78
|
+
const address = typeof agentOrAddress === 'string'
|
|
79
|
+
? agentOrAddress
|
|
80
|
+
: agentOrAddress.address;
|
|
81
|
+
|
|
82
|
+
cliLogger.progress(`[Team] Resolving MCP: ${address}...`);
|
|
83
|
+
|
|
84
|
+
// Check cache
|
|
85
|
+
if (this.team._mcpResolved.has(address)) {
|
|
86
|
+
agent = this.team._mcpResolved.get(address);
|
|
87
|
+
cliLogger.clear();
|
|
88
|
+
} else {
|
|
89
|
+
// Resolve the MCP address
|
|
90
|
+
try {
|
|
91
|
+
agent = await mcpClient.resolve(address);
|
|
92
|
+
this.team._mcpResolved.set(address, agent);
|
|
93
|
+
cliLogger.clear();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
cliLogger.error(`[Team] Failed to resolve ${address}: ${error.message}`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check role filter
|
|
102
|
+
if (this.roleFilter && agent.role !== this.roleFilter) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Check if agent has handler for this event
|
|
107
|
+
if (agent.handlers && agent.handlers[this.eventName]) {
|
|
108
|
+
candidates.push({ name, agent });
|
|
109
|
+
} else if (!agent.handlers && typeof agent.handle === 'function') {
|
|
110
|
+
// MCP resources (not regular agents) have a generic handle method
|
|
111
|
+
candidates.push({ name, agent });
|
|
112
|
+
} else if (!agent.handlers && typeof agent.send === 'function') {
|
|
113
|
+
// MCP resources may also have a send method
|
|
114
|
+
candidates.push({ name, agent });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (candidates.length === 0) {
|
|
119
|
+
const roleInfo = this.roleFilter ? ` with role "${this.roleFilter.name}"` : '';
|
|
120
|
+
throw new Error(`NO_AGENT_HANDLER:${this.eventName}:${roleInfo}:${this.team.name}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Execute based on selection mode
|
|
124
|
+
if (this.selectionMode === 'any') {
|
|
125
|
+
const selected = candidates[0];
|
|
126
|
+
const agentName = selected.agent.name || selected.name;
|
|
127
|
+
|
|
128
|
+
// Show delegation
|
|
129
|
+
cliLogger.progress(` → [${agentName}] ${this.eventName}...`);
|
|
130
|
+
|
|
131
|
+
// Handle both regular agents and MCP resources
|
|
132
|
+
let result;
|
|
133
|
+
if (selected.agent.handle) {
|
|
134
|
+
// Don't mark as delegation - let the agent decide based on its own context
|
|
135
|
+
result = await selected.agent.handle(this.eventName, args, false);
|
|
136
|
+
} else if (selected.agent.send) {
|
|
137
|
+
result = await selected.agent.send(this.eventName, args);
|
|
138
|
+
} else {
|
|
139
|
+
throw new Error(`Agent ${selected.name} cannot handle event ${this.eventName}`);
|
|
140
|
+
}
|
|
141
|
+
cliLogger.clear();
|
|
142
|
+
return result;
|
|
143
|
+
} else if (this.selectionMode === 'all') {
|
|
144
|
+
const results = [];
|
|
145
|
+
for (const { name, agent } of candidates) {
|
|
146
|
+
const agentName = agent.name || name;
|
|
147
|
+
cliLogger.progress(` → [${agentName}] ${this.eventName}...`);
|
|
148
|
+
|
|
149
|
+
if (agent.handle) {
|
|
150
|
+
// Don't mark as delegation - let the agent decide based on its own context
|
|
151
|
+
results.push(await agent.handle(this.eventName, args, false));
|
|
152
|
+
} else if (agent.send) {
|
|
153
|
+
results.push(await agent.send(this.eventName, args));
|
|
154
|
+
}
|
|
155
|
+
cliLogger.clear();
|
|
156
|
+
}
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
throw new Error(`Selection mode not specified (use .any() or .all())`);
|
|
161
|
+
}
|
|
162
|
+
}
|