@mcoda/codali 0.1.108 → 0.1.110
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/dist/agents/AgentInventory.d.ts +56 -0
- package/dist/agents/AgentInventory.d.ts.map +1 -0
- package/dist/agents/AgentInventory.js +131 -0
- package/dist/agents/RoleResolution.d.ts +49 -0
- package/dist/agents/RoleResolution.d.ts.map +1 -0
- package/dist/agents/RoleResolution.js +166 -0
- package/dist/api/ChatCompletionsAdapter.d.ts +76 -0
- package/dist/api/ChatCompletionsAdapter.d.ts.map +1 -0
- package/dist/api/ChatCompletionsAdapter.js +54 -0
- package/dist/api/CodaliApi.d.ts +78 -0
- package/dist/api/CodaliApi.d.ts.map +1 -0
- package/dist/api/CodaliApi.js +273 -0
- package/dist/api/CodaliServer.d.ts +42 -0
- package/dist/api/CodaliServer.d.ts.map +1 -0
- package/dist/api/CodaliServer.js +118 -0
- package/dist/cli/AskCommand.d.ts +66 -0
- package/dist/cli/AskCommand.d.ts.map +1 -0
- package/dist/cli/AskCommand.js +536 -0
- package/dist/cli/AuthCommand.d.ts +19 -0
- package/dist/cli/AuthCommand.d.ts.map +1 -0
- package/dist/cli/AuthCommand.js +161 -0
- package/dist/cli/ServeCommand.d.ts +5 -0
- package/dist/cli/ServeCommand.d.ts.map +1 -0
- package/dist/cli/ServeCommand.js +87 -0
- package/dist/cli/ToolsCommand.d.ts +22 -0
- package/dist/cli/ToolsCommand.d.ts.map +1 -0
- package/dist/cli/ToolsCommand.js +208 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -1
- package/dist/connectors/http/HttpToolDefinition.d.ts +74 -0
- package/dist/connectors/http/HttpToolDefinition.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolDefinition.js +190 -0
- package/dist/connectors/http/HttpToolSource.d.ts +18 -0
- package/dist/connectors/http/HttpToolSource.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolSource.js +29 -0
- package/dist/connectors/mcp/McpClient.d.ts +132 -0
- package/dist/connectors/mcp/McpClient.d.ts.map +1 -0
- package/dist/connectors/mcp/McpClient.js +215 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts +75 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
- package/dist/connectors/mcp/McpServerRegistry.js +180 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts +48 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolAdapter.js +101 -0
- package/dist/connectors/mcp/McpToolSource.d.ts +27 -0
- package/dist/connectors/mcp/McpToolSource.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolSource.js +33 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts +43 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts.map +1 -0
- package/dist/connectors/media/ImageGenerationTool.js +122 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
- package/dist/connectors/oauth/DeviceCodeAuth.js +153 -0
- package/dist/docdex/DocdexClient.d.ts +2 -0
- package/dist/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/docdex/DocdexClient.js +4 -0
- package/dist/gateway/CodaliGateway.d.ts +51 -3
- package/dist/gateway/CodaliGateway.d.ts.map +1 -1
- package/dist/gateway/CodaliGateway.js +241 -3
- package/dist/gateway/CodaliGatewayTypes.d.ts +34 -0
- package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.js +98 -1
- package/dist/gateway/Finalizer.d.ts +50 -0
- package/dist/gateway/Finalizer.d.ts.map +1 -0
- package/dist/gateway/Finalizer.js +79 -0
- package/dist/gateway/GatewayPlanner.d.ts +13 -0
- package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
- package/dist/gateway/GatewayPlanner.js +81 -16
- package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
- package/dist/gateway/GatewayStateMachine.js +6 -0
- package/dist/gateway/GatewayTracer.d.ts +93 -0
- package/dist/gateway/GatewayTracer.d.ts.map +1 -0
- package/dist/gateway/GatewayTracer.js +214 -0
- package/dist/gateway/LocalGatewayProvider.d.ts +59 -0
- package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayProvider.js +195 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayTaskRunner.js +361 -0
- package/dist/gateway/RelevanceJudge.d.ts +25 -0
- package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
- package/dist/gateway/RelevanceJudge.js +124 -0
- package/dist/gateway/ResponseSchema.d.ts +32 -0
- package/dist/gateway/ResponseSchema.d.ts.map +1 -0
- package/dist/gateway/ResponseSchema.js +120 -0
- package/dist/gateway/TemporalContext.d.ts +36 -0
- package/dist/gateway/TemporalContext.d.ts.map +1 -0
- package/dist/gateway/TemporalContext.js +115 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts +5 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
- package/dist/gateway/ToolCapabilityCompiler.js +27 -2
- package/dist/gateway/ToolDescriptorSource.d.ts +6 -0
- package/dist/gateway/ToolDescriptorSource.d.ts.map +1 -0
- package/dist/gateway/ToolDescriptorSource.js +30 -0
- package/dist/gateway/ToolExposure.d.ts +36 -0
- package/dist/gateway/ToolExposure.d.ts.map +1 -0
- package/dist/gateway/ToolExposure.js +154 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -0
- package/dist/providers/ClaudeCliProvider.d.ts +2 -0
- package/dist/providers/ClaudeCliProvider.d.ts.map +1 -1
- package/dist/providers/ClaudeCliProvider.js +2 -0
- package/dist/providers/CodexCliProvider.d.ts +2 -0
- package/dist/providers/CodexCliProvider.d.ts.map +1 -1
- package/dist/providers/CodexCliProvider.js +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
- package/dist/providers/MswarmWorkerProvider.js +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts.map +1 -1
- package/dist/providers/OllamaRemoteProvider.js +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
- package/dist/providers/OpenAiCompatibleProvider.js +2 -0
- package/dist/providers/ProviderTypes.d.ts +13 -0
- package/dist/providers/ProviderTypes.d.ts.map +1 -1
- package/dist/providers/ProviderTypes.js +1 -1
- package/dist/runcontext/CredentialFile.d.ts +12 -0
- package/dist/runcontext/CredentialFile.d.ts.map +1 -0
- package/dist/runcontext/CredentialFile.js +81 -0
- package/dist/runcontext/RunContextResolver.d.ts +126 -0
- package/dist/runcontext/RunContextResolver.d.ts.map +1 -0
- package/dist/runcontext/RunContextResolver.js +389 -0
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.js +12 -0
- package/dist/tools/ToolRegistry.d.ts +14 -1
- package/dist/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/tools/ToolRegistry.js +38 -1
- package/dist/tools/ToolTypes.d.ts +35 -0
- package/dist/tools/ToolTypes.d.ts.map +1 -1
- package/dist/tools/ToolTypes.js +21 -0
- package/dist/tools/TruncateResult.d.ts +29 -0
- package/dist/tools/TruncateResult.d.ts.map +1 -0
- package/dist/tools/TruncateResult.js +91 -0
- package/dist/tools/diff/DiffTool.d.ts.map +1 -1
- package/dist/tools/diff/DiffTool.js +2 -0
- package/dist/tools/docdex/DocdexTools.d.ts +21 -1
- package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
- package/dist/tools/docdex/DocdexTools.js +151 -17
- package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
- package/dist/tools/filesystem/FileTools.js +8 -0
- package/dist/tools/search/SearchTool.d.ts.map +1 -1
- package/dist/tools/search/SearchTool.js +3 -1
- package/dist/tools/shell/ShellTool.d.ts.map +1 -1
- package/dist/tools/shell/ShellTool.js +2 -0
- package/package.json +4 -3
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal run tracing.
|
|
3
|
+
*
|
|
4
|
+
* This ships with the first executable version rather than being deferred to a
|
|
5
|
+
* later observability phase. Tool-selection and iteration failures are the two
|
|
6
|
+
* things most likely to go wrong in an orchestrator, and both are close to
|
|
7
|
+
* undiagnosable without a record of what was chosen and why. Full trace replay
|
|
8
|
+
* can wait; knowing which model ran, which tools it picked, and why the run
|
|
9
|
+
* stopped cannot.
|
|
10
|
+
*
|
|
11
|
+
* Arguments are sanitized before they are recorded, because tool arguments
|
|
12
|
+
* routinely carry tokens and paths that must not reach a log.
|
|
13
|
+
*/
|
|
14
|
+
const SENSITIVE_KEY_PATTERN = /(?:authorization|api[_-]?key|bearer|credential|password|secret|signature|token)/i;
|
|
15
|
+
/**
|
|
16
|
+
* Secret shapes redacted from *values*, not just from suspiciously named keys.
|
|
17
|
+
*
|
|
18
|
+
* A connector routinely returns a token inside an innocuously named field, and
|
|
19
|
+
* an MCP tool's arguments are model-generated, so key-name matching alone is
|
|
20
|
+
* not enough. These mirror the dataset privacy engine's patterns; both must
|
|
21
|
+
* catch a leak, because the trace is what gets printed to a terminal and pasted
|
|
22
|
+
* into an issue.
|
|
23
|
+
*/
|
|
24
|
+
const SENSITIVE_VALUE_PATTERNS = [
|
|
25
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]{12,}/gi,
|
|
26
|
+
/\bsk-[A-Za-z0-9_-]{16,}\b/g,
|
|
27
|
+
/\bsk_[A-Za-z0-9]+_[A-Za-z0-9_]{8,}\b/g,
|
|
28
|
+
/\bgh[pousr]_[A-Za-z0-9_]{20,}\b/g,
|
|
29
|
+
/\bglpat-[A-Za-z0-9_-]{16,}\b/g,
|
|
30
|
+
/\bxox[abprs]-[A-Za-z0-9-]{10,}\b/g,
|
|
31
|
+
/\bAKIA[0-9A-Z]{16}\b/g,
|
|
32
|
+
/\bAIza[0-9A-Za-z_-]{30,}\b/g,
|
|
33
|
+
/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g,
|
|
34
|
+
];
|
|
35
|
+
export const redactSecretValues = (value) => {
|
|
36
|
+
let output = value;
|
|
37
|
+
for (const pattern of SENSITIVE_VALUE_PATTERNS) {
|
|
38
|
+
output = output.replace(pattern, "[redacted]");
|
|
39
|
+
}
|
|
40
|
+
return output;
|
|
41
|
+
};
|
|
42
|
+
const MAX_ARG_STRING = 200;
|
|
43
|
+
/**
|
|
44
|
+
* Redacts sensitive-looking values and truncates long ones. Applied to every
|
|
45
|
+
* argument before it is recorded or printed.
|
|
46
|
+
*/
|
|
47
|
+
export const sanitizeArgs = (value, depth = 0) => {
|
|
48
|
+
if (depth > 4)
|
|
49
|
+
return "[depth limit]";
|
|
50
|
+
if (typeof value === "string") {
|
|
51
|
+
// Redact before truncating: truncation could otherwise cut a secret in half
|
|
52
|
+
// and leave a recognizable prefix in the trace.
|
|
53
|
+
const redacted = redactSecretValues(value);
|
|
54
|
+
return redacted.length > MAX_ARG_STRING
|
|
55
|
+
? `${redacted.slice(0, MAX_ARG_STRING)}…`
|
|
56
|
+
: redacted;
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
return value.slice(0, 20).map((entry) => sanitizeArgs(entry, depth + 1));
|
|
60
|
+
}
|
|
61
|
+
if (value && typeof value === "object") {
|
|
62
|
+
const output = {};
|
|
63
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
64
|
+
output[key] = SENSITIVE_KEY_PATTERN.test(key)
|
|
65
|
+
? "[redacted]"
|
|
66
|
+
: sanitizeArgs(entry, depth + 1);
|
|
67
|
+
}
|
|
68
|
+
return output;
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
};
|
|
72
|
+
export class GatewayTracer {
|
|
73
|
+
constructor(query, options = {}) {
|
|
74
|
+
this.options = options;
|
|
75
|
+
this.startedMs = Date.now();
|
|
76
|
+
this.record = {
|
|
77
|
+
query,
|
|
78
|
+
startedAt: new Date().toISOString(),
|
|
79
|
+
roleBindings: {},
|
|
80
|
+
plannedTasks: [],
|
|
81
|
+
toolCalls: [],
|
|
82
|
+
rounds: 0,
|
|
83
|
+
warnings: [],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
emit(line) {
|
|
87
|
+
if (!this.options.verbose)
|
|
88
|
+
return;
|
|
89
|
+
(this.options.write ?? ((text) => process.stderr.write(`${text}\n`)))(line);
|
|
90
|
+
}
|
|
91
|
+
setRunId(runId) {
|
|
92
|
+
this.record.runId = runId;
|
|
93
|
+
}
|
|
94
|
+
setRoleBindings(bindings) {
|
|
95
|
+
for (const [role, slug] of Object.entries(bindings)) {
|
|
96
|
+
if (slug)
|
|
97
|
+
this.record.roleBindings[role] = slug;
|
|
98
|
+
}
|
|
99
|
+
const rendered = Object.entries(this.record.roleBindings)
|
|
100
|
+
.map(([role, slug]) => `${role}=${slug}`)
|
|
101
|
+
.join(" ");
|
|
102
|
+
if (rendered)
|
|
103
|
+
this.emit(`· agents: ${rendered}`);
|
|
104
|
+
}
|
|
105
|
+
recordPlan(input) {
|
|
106
|
+
this.record.capabilities = input.capabilities;
|
|
107
|
+
this.record.plannedTasks = input.tasks.map((task) => ({
|
|
108
|
+
id: task.id,
|
|
109
|
+
role: task.workerRole,
|
|
110
|
+
objective: task.objective,
|
|
111
|
+
tools: task.toolsAllowed ?? [],
|
|
112
|
+
}));
|
|
113
|
+
if (input.capabilities?.length) {
|
|
114
|
+
this.emit(`· capabilities: ${input.capabilities.join(", ")}`);
|
|
115
|
+
}
|
|
116
|
+
this.emit(this.record.plannedTasks.length === 0
|
|
117
|
+
? "· plan: answer directly, no tool tasks"
|
|
118
|
+
: `· plan: ${this.record.plannedTasks.length} task(s)`);
|
|
119
|
+
for (const task of this.record.plannedTasks) {
|
|
120
|
+
this.emit(` ${task.id} [${task.role}] ${task.objective}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
recordToolCall(input) {
|
|
124
|
+
this.record.toolCalls.push({
|
|
125
|
+
taskId: input.taskId,
|
|
126
|
+
tool: input.tool,
|
|
127
|
+
args: sanitizeArgs(input.args),
|
|
128
|
+
});
|
|
129
|
+
this.emit(`· tool → ${input.tool} ${JSON.stringify(sanitizeArgs(input.args))}`);
|
|
130
|
+
}
|
|
131
|
+
recordToolResult(input) {
|
|
132
|
+
// Attach to the most recent matching call rather than appending a row, so
|
|
133
|
+
// the trace reads as one line per call.
|
|
134
|
+
for (let index = this.record.toolCalls.length - 1; index >= 0; index -= 1) {
|
|
135
|
+
const call = this.record.toolCalls[index];
|
|
136
|
+
if (call && call.tool === input.tool && call.ok === undefined) {
|
|
137
|
+
call.ok = input.ok;
|
|
138
|
+
call.latencyMs = input.latencyMs;
|
|
139
|
+
call.errorCode = input.errorCode;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
this.emit(`· tool ← ${input.tool} ${input.ok ? "ok" : `failed (${input.errorCode ?? "unknown"})`} ${input.latencyMs}ms`);
|
|
144
|
+
}
|
|
145
|
+
recordRound(round) {
|
|
146
|
+
this.record.rounds = Math.max(this.record.rounds, round);
|
|
147
|
+
this.emit(`· round ${round}`);
|
|
148
|
+
}
|
|
149
|
+
addWarning(warning) {
|
|
150
|
+
this.record.warnings.push(warning);
|
|
151
|
+
}
|
|
152
|
+
finish(input) {
|
|
153
|
+
this.record.status = input.status;
|
|
154
|
+
this.record.finalizerMode = input.finalizerMode;
|
|
155
|
+
this.record.completionReason = input.completionReason;
|
|
156
|
+
this.record.warnings.push(...(input.warnings ?? []));
|
|
157
|
+
this.record.durationMs = Date.now() - this.startedMs;
|
|
158
|
+
this.emit(`· done: ${input.status}${input.finalizerMode ? ` via ${input.finalizerMode}` : ""} in ${this.record.durationMs}ms (${this.record.toolCalls.length} tool calls)`);
|
|
159
|
+
return this.record;
|
|
160
|
+
}
|
|
161
|
+
snapshot() {
|
|
162
|
+
return this.record;
|
|
163
|
+
}
|
|
164
|
+
/** Human-readable summary printed by `codali ask --trace`. */
|
|
165
|
+
render() {
|
|
166
|
+
const lines = [];
|
|
167
|
+
lines.push(`run: ${this.record.runId ?? "(unassigned)"}`);
|
|
168
|
+
lines.push(`status: ${this.record.status ?? "unknown"}`);
|
|
169
|
+
if (this.record.completionReason) {
|
|
170
|
+
lines.push(`completion: ${this.record.completionReason}`);
|
|
171
|
+
}
|
|
172
|
+
if (this.record.finalizerMode) {
|
|
173
|
+
lines.push(`finalizer: ${this.record.finalizerMode}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push(`duration: ${this.record.durationMs ?? 0}ms`);
|
|
176
|
+
lines.push(`rounds: ${this.record.rounds}`);
|
|
177
|
+
const bindings = Object.entries(this.record.roleBindings);
|
|
178
|
+
if (bindings.length > 0) {
|
|
179
|
+
lines.push("agents:");
|
|
180
|
+
for (const [role, slug] of bindings)
|
|
181
|
+
lines.push(` ${role}: ${slug}`);
|
|
182
|
+
}
|
|
183
|
+
if (this.record.capabilities?.length) {
|
|
184
|
+
lines.push(`capabilities: ${this.record.capabilities.join(", ")}`);
|
|
185
|
+
}
|
|
186
|
+
if (this.record.plannedTasks.length > 0) {
|
|
187
|
+
lines.push("tasks:");
|
|
188
|
+
for (const task of this.record.plannedTasks) {
|
|
189
|
+
lines.push(` ${task.id} [${task.role}] tools=${task.tools.join(",") || "none"}`);
|
|
190
|
+
lines.push(` ${task.objective}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (this.record.toolCalls.length > 0) {
|
|
194
|
+
lines.push("tool calls:");
|
|
195
|
+
for (const call of this.record.toolCalls) {
|
|
196
|
+
const status = call.ok === undefined
|
|
197
|
+
? "pending"
|
|
198
|
+
: call.ok
|
|
199
|
+
? "ok"
|
|
200
|
+
: `failed(${call.errorCode ?? "unknown"})`;
|
|
201
|
+
lines.push(` ${call.tool} ${status} ${call.latencyMs ?? 0}ms ${JSON.stringify(call.args)}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
lines.push("tool calls: none");
|
|
206
|
+
}
|
|
207
|
+
if (this.record.warnings.length > 0) {
|
|
208
|
+
lines.push("warnings:");
|
|
209
|
+
for (const warning of this.record.warnings)
|
|
210
|
+
lines.push(` ${warning}`);
|
|
211
|
+
}
|
|
212
|
+
return lines.join("\n");
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { Provider, ProviderConfig } from "../providers/ProviderTypes.js";
|
|
2
|
+
import type { CodaliGatewayAgentAssignment } from "./AgentTierResolver.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds a `Provider` from a resolved mcoda agent so the gateway can run
|
|
5
|
+
* in-process from the CLI, without a round trip through mswarm.
|
|
6
|
+
*
|
|
7
|
+
* mswarm keeps its own cloud path; both should end up sharing this factory so
|
|
8
|
+
* local and cloud behaviour cannot drift.
|
|
9
|
+
*/
|
|
10
|
+
export interface LocalProviderOptions {
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
apiKey?: string;
|
|
13
|
+
/** Scheduling priority; lower runs sooner. Defaults to CODALI_MSWARM_PRIORITY. */
|
|
14
|
+
priority?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Scheduling priority Codali asks mswarm for.
|
|
18
|
+
*
|
|
19
|
+
* mswarm sorts ascending, so a lower number runs sooner, and its nodes reserve
|
|
20
|
+
* capacity for priority <= -1. Codali runs are interactive — someone is waiting
|
|
21
|
+
* at a terminal or in a chat window — so they should not queue behind batch
|
|
22
|
+
* work. -10 sits comfortably inside the reserved band without claiming the
|
|
23
|
+
* extreme of the -100..100 range, leaving room for anything genuinely more
|
|
24
|
+
* urgent.
|
|
25
|
+
*/
|
|
26
|
+
export declare const CODALI_MSWARM_PRIORITY = -10;
|
|
27
|
+
/**
|
|
28
|
+
* mcoda adapter -> Codali provider. Adapters not listed fall through to the
|
|
29
|
+
* OpenAI-compatible provider, which is the correct default for local runners
|
|
30
|
+
* (llama.cpp, vLLM, LocalAI) and most hosted endpoints.
|
|
31
|
+
*/
|
|
32
|
+
export declare const providerNameForAdapter: (adapter: string | undefined) => string;
|
|
33
|
+
export declare const createProviderForName: (name: string, config: ProviderConfig) => Provider;
|
|
34
|
+
export declare const resolveMswarmApiKey: () => string | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a provider for an assigned agent. The raw inventory entry carries the
|
|
37
|
+
* transport details (base URL, runner kind, auth mode) that the tier resolver
|
|
38
|
+
* does not model, so it is read here.
|
|
39
|
+
*/
|
|
40
|
+
export declare const createProviderForAssignment: (assignment: CodaliGatewayAgentAssignment, options?: LocalProviderOptions) => Provider;
|
|
41
|
+
/**
|
|
42
|
+
* Routes each gateway role to its own provider.
|
|
43
|
+
*
|
|
44
|
+
* Codali's whole premise is that a small model does the errands and a large one
|
|
45
|
+
* writes the answer. A single shared provider would silently collapse that: the
|
|
46
|
+
* planner and the synthesizer would run on the same model and the cost/quality
|
|
47
|
+
* split would be lost. So role dispatch is explicit, with a declared fallback
|
|
48
|
+
* rather than an accidental one.
|
|
49
|
+
*/
|
|
50
|
+
export declare class RoleRoutingProvider implements Provider {
|
|
51
|
+
private readonly providers;
|
|
52
|
+
private readonly fallback;
|
|
53
|
+
private readonly resolveRole;
|
|
54
|
+
readonly name = "codali-role-router";
|
|
55
|
+
constructor(providers: Record<string, Provider>, fallback: Provider, resolveRole?: () => string | undefined);
|
|
56
|
+
providerForRole(role: string | undefined): Provider;
|
|
57
|
+
generate(request: Parameters<Provider["generate"]>[0]): ReturnType<Provider["generate"]>;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=LocalGatewayProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalGatewayProvider.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAE3E;;;;;;GAMG;AAEH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0CD;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAwB1C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,MAapE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,QAAQ,cAAc,KACrB,QAWF,CAAC;AAYF,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,SA4B/C,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,YAAY,4BAA4B,EACxC,UAAS,oBAAyB,KACjC,QAkCF,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAIhD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAL9B,QAAQ,CAAC,IAAI,wBAAwB;gBAGlB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,QAAQ,EAAE,QAAQ,EAClB,WAAW,GAAE,MAAM,MAAM,GAAG,SAA2B;IAG1E,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ;IAK7C,QAAQ,CACZ,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3C,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;CAGpC"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { ClaudeCliProvider } from "../providers/ClaudeCliProvider.js";
|
|
5
|
+
import { CodexCliProvider } from "../providers/CodexCliProvider.js";
|
|
6
|
+
import { OllamaRemoteProvider } from "../providers/OllamaRemoteProvider.js";
|
|
7
|
+
import { OpenAiCompatibleProvider } from "../providers/OpenAiCompatibleProvider.js";
|
|
8
|
+
/**
|
|
9
|
+
* Attaches the scheduling priority mswarm reads from `scheduling.priority`,
|
|
10
|
+
* without disturbing any runner settings the agent already carries.
|
|
11
|
+
*/
|
|
12
|
+
const buildLocalRunner = (nested, baseUrl, priority) => {
|
|
13
|
+
const existing = isRecord(nested.localRunner)
|
|
14
|
+
? nested.localRunner
|
|
15
|
+
: undefined;
|
|
16
|
+
if (!isMswarmEndpoint(baseUrl)) {
|
|
17
|
+
return existing;
|
|
18
|
+
}
|
|
19
|
+
const existingExtra = isRecord(existing?.extraBody) ? existing.extraBody : {};
|
|
20
|
+
const existingScheduling = isRecord(existingExtra.scheduling) ? existingExtra.scheduling : {};
|
|
21
|
+
return {
|
|
22
|
+
...(existing ?? {}),
|
|
23
|
+
extraBody: {
|
|
24
|
+
...existingExtra,
|
|
25
|
+
scheduling: {
|
|
26
|
+
...existingScheduling,
|
|
27
|
+
// An explicit value in the agent config wins over the default.
|
|
28
|
+
priority: existingScheduling.priority ?? priority ?? CODALI_MSWARM_PRIORITY,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Request timeout for a locally-hosted model.
|
|
35
|
+
*
|
|
36
|
+
* The providers default to 60s, which suits a hosted API and not a local one:
|
|
37
|
+
* qwen3.6 on the self-hosted node takes ~47s for a one-line prompt, so a full
|
|
38
|
+
* context pack aborted every time and surfaced as "the final model was
|
|
39
|
+
* unavailable" — a timeout wearing the costume of an outage.
|
|
40
|
+
*/
|
|
41
|
+
const LOCAL_MODEL_TIMEOUT_MS = 600000;
|
|
42
|
+
/**
|
|
43
|
+
* Scheduling priority Codali asks mswarm for.
|
|
44
|
+
*
|
|
45
|
+
* mswarm sorts ascending, so a lower number runs sooner, and its nodes reserve
|
|
46
|
+
* capacity for priority <= -1. Codali runs are interactive — someone is waiting
|
|
47
|
+
* at a terminal or in a chat window — so they should not queue behind batch
|
|
48
|
+
* work. -10 sits comfortably inside the reserved band without claiming the
|
|
49
|
+
* extreme of the -100..100 range, leaving room for anything genuinely more
|
|
50
|
+
* urgent.
|
|
51
|
+
*/
|
|
52
|
+
export const CODALI_MSWARM_PRIORITY = -10;
|
|
53
|
+
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
54
|
+
const readString = (record, keys) => {
|
|
55
|
+
for (const key of keys) {
|
|
56
|
+
const value = record[key];
|
|
57
|
+
if (typeof value === "string" && value.trim())
|
|
58
|
+
return value.trim();
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
};
|
|
62
|
+
const readBoolean = (record, keys) => {
|
|
63
|
+
for (const key of keys) {
|
|
64
|
+
const value = record[key];
|
|
65
|
+
if (typeof value === "boolean")
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* mcoda adapter -> Codali provider. Adapters not listed fall through to the
|
|
72
|
+
* OpenAI-compatible provider, which is the correct default for local runners
|
|
73
|
+
* (llama.cpp, vLLM, LocalAI) and most hosted endpoints.
|
|
74
|
+
*/
|
|
75
|
+
export const providerNameForAdapter = (adapter) => {
|
|
76
|
+
switch ((adapter ?? "").toLowerCase()) {
|
|
77
|
+
case "claude-cli":
|
|
78
|
+
return "claude-cli";
|
|
79
|
+
case "codex-cli":
|
|
80
|
+
return "codex-cli";
|
|
81
|
+
case "ollama-cli":
|
|
82
|
+
case "ollama-remote":
|
|
83
|
+
case "ollama":
|
|
84
|
+
return "ollama";
|
|
85
|
+
default:
|
|
86
|
+
return "openai-compatible";
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export const createProviderForName = (name, config) => {
|
|
90
|
+
switch (name) {
|
|
91
|
+
case "claude-cli":
|
|
92
|
+
return new ClaudeCliProvider(config);
|
|
93
|
+
case "codex-cli":
|
|
94
|
+
return new CodexCliProvider(config);
|
|
95
|
+
case "ollama":
|
|
96
|
+
return new OllamaRemoteProvider(config);
|
|
97
|
+
default:
|
|
98
|
+
return new OpenAiCompatibleProvider(config);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* The mswarm API key, used to reach self-hosted agents served through the
|
|
103
|
+
* mswarm gateway. `mcoda agent list --json` reports `auth.configured: true` but
|
|
104
|
+
* never discloses the key itself, so it is read from local trusted config.
|
|
105
|
+
*
|
|
106
|
+
* Local CLI only. A multi-tenant deployment must receive credentials from its
|
|
107
|
+
* host rather than reading the operator's files.
|
|
108
|
+
*/
|
|
109
|
+
let cachedMswarmKey;
|
|
110
|
+
export const resolveMswarmApiKey = () => {
|
|
111
|
+
if (cachedMswarmKey !== undefined)
|
|
112
|
+
return cachedMswarmKey ?? undefined;
|
|
113
|
+
const fromEnv = process.env.MSWARM_API_KEY?.trim();
|
|
114
|
+
if (fromEnv) {
|
|
115
|
+
cachedMswarmKey = fromEnv;
|
|
116
|
+
return fromEnv;
|
|
117
|
+
}
|
|
118
|
+
const configPath = path.join(homedir(), ".docdex", "config.toml");
|
|
119
|
+
if (existsSync(configPath)) {
|
|
120
|
+
try {
|
|
121
|
+
const raw = readFileSync(configPath, "utf8");
|
|
122
|
+
// Minimal TOML read: find api_key inside [integrations.mswarm].
|
|
123
|
+
const section = raw.split(/^\[integrations\.mswarm\]\s*$/m)[1];
|
|
124
|
+
const match = section?.match(/^\s*api_key\s*=\s*"([^"]+)"/m);
|
|
125
|
+
if (match?.[1]) {
|
|
126
|
+
cachedMswarmKey = match[1];
|
|
127
|
+
return cachedMswarmKey;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Unreadable config is not fatal; the provider will fail with a clearer
|
|
132
|
+
// authentication error than anything we could raise here.
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
cachedMswarmKey = null;
|
|
136
|
+
return undefined;
|
|
137
|
+
};
|
|
138
|
+
const isMswarmEndpoint = (baseUrl) => Boolean(baseUrl && /(^|\/\/)([^/]*\.)?mswarm\.org/i.test(baseUrl));
|
|
139
|
+
/**
|
|
140
|
+
* Creates a provider for an assigned agent. The raw inventory entry carries the
|
|
141
|
+
* transport details (base URL, runner kind, auth mode) that the tier resolver
|
|
142
|
+
* does not model, so it is read here.
|
|
143
|
+
*/
|
|
144
|
+
export const createProviderForAssignment = (assignment, options = {}) => {
|
|
145
|
+
const raw = isRecord(assignment.candidate.raw) ? assignment.candidate.raw : {};
|
|
146
|
+
// mcoda nests transport details under `config`; older entries put them at the
|
|
147
|
+
// top level. Read both, preferring the nested form.
|
|
148
|
+
const nested = isRecord(raw.config) ? raw.config : {};
|
|
149
|
+
const adapter = assignment.candidate.adapter ?? readString(raw, ["adapter"]);
|
|
150
|
+
const providerName = providerNameForAdapter(adapter);
|
|
151
|
+
const baseUrl = readString(nested, ["baseUrl", "base_url", "apiBaseUrl", "api_base_url"]) ??
|
|
152
|
+
readString(raw, ["baseUrl", "base_url"]);
|
|
153
|
+
const apiKey = options.apiKey ??
|
|
154
|
+
readString(nested, ["apiKey", "api_key"]) ??
|
|
155
|
+
readString(raw, ["apiKey", "api_key"]) ??
|
|
156
|
+
(isMswarmEndpoint(baseUrl) ? resolveMswarmApiKey() : undefined);
|
|
157
|
+
const config = {
|
|
158
|
+
model: assignment.candidate.model ?? readString(raw, ["defaultModel", "model"]) ?? "",
|
|
159
|
+
baseUrl,
|
|
160
|
+
apiKey,
|
|
161
|
+
timeoutMs: options.timeoutMs ?? LOCAL_MODEL_TIMEOUT_MS,
|
|
162
|
+
runnerKind: readString(nested, ["runnerKind", "runner_kind"]),
|
|
163
|
+
authMode: readString(nested, ["authMode", "auth_mode"]),
|
|
164
|
+
localRunner: buildLocalRunner(nested, baseUrl, options.priority),
|
|
165
|
+
supportsTools: assignment.candidate.supportsTools ?? readBoolean(raw, ["supportsTools"]),
|
|
166
|
+
supportsJsonSchema: assignment.candidate.supportsJsonSchema ?? readBoolean(raw, ["supportsJsonSchema"]),
|
|
167
|
+
supportsStreaming: assignment.candidate.supportsStreaming ?? readBoolean(raw, ["supportsStreaming"]),
|
|
168
|
+
};
|
|
169
|
+
return createProviderForName(providerName, config);
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* Routes each gateway role to its own provider.
|
|
173
|
+
*
|
|
174
|
+
* Codali's whole premise is that a small model does the errands and a large one
|
|
175
|
+
* writes the answer. A single shared provider would silently collapse that: the
|
|
176
|
+
* planner and the synthesizer would run on the same model and the cost/quality
|
|
177
|
+
* split would be lost. So role dispatch is explicit, with a declared fallback
|
|
178
|
+
* rather than an accidental one.
|
|
179
|
+
*/
|
|
180
|
+
export class RoleRoutingProvider {
|
|
181
|
+
constructor(providers, fallback, resolveRole = () => undefined) {
|
|
182
|
+
this.providers = providers;
|
|
183
|
+
this.fallback = fallback;
|
|
184
|
+
this.resolveRole = resolveRole;
|
|
185
|
+
this.name = "codali-role-router";
|
|
186
|
+
}
|
|
187
|
+
providerForRole(role) {
|
|
188
|
+
if (!role)
|
|
189
|
+
return this.fallback;
|
|
190
|
+
return this.providers[role] ?? this.fallback;
|
|
191
|
+
}
|
|
192
|
+
async generate(request) {
|
|
193
|
+
return this.providerForRole(this.resolveRole()).generate(request);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Provider } from "../providers/ProviderTypes.js";
|
|
2
|
+
import type { ToolRegistry } from "../tools/ToolRegistry.js";
|
|
3
|
+
import type { ToolContext } from "../tools/ToolTypes.js";
|
|
4
|
+
import type { CodaliGatewayWorkerTaskRunInput, CodaliGatewayWorkerTaskRunResult, CodaliGatewayWorkerTaskRunner } from "./GatewayStateMachine.js";
|
|
5
|
+
/**
|
|
6
|
+
* Bounded worker-task runner.
|
|
7
|
+
*
|
|
8
|
+
* ## Why this exists
|
|
9
|
+
*
|
|
10
|
+
* Codali previously executed every gateway worker task by handing it to the
|
|
11
|
+
* full `CodaliRuntime` agent loop (see `createGatewayTaskRunner` in
|
|
12
|
+
* `packages/mswarm/src/codali-executor.ts`). That nested one open-ended loop
|
|
13
|
+
* inside another: the gateway decided how many *rounds* to run, while the
|
|
14
|
+
* runtime independently decided how many *steps* to take inside each task.
|
|
15
|
+
* Neither could bound the other, so a single request could fan out
|
|
16
|
+
* unpredictably and a runaway task was near-impossible to attribute.
|
|
17
|
+
*
|
|
18
|
+
* This runner removes the inner loop. Exactly one component - the gateway state
|
|
19
|
+
* machine - owns iteration. A task here is a single bounded pass:
|
|
20
|
+
*
|
|
21
|
+
* 1. ask the model what it needs (one model call)
|
|
22
|
+
* 2. execute the tool calls it asked for, in parallel where independent
|
|
23
|
+
* 3. ask the model to turn the results into the task output (one model call)
|
|
24
|
+
*
|
|
25
|
+
* There is no step 4 and no "decide whether to keep going". If the evidence is
|
|
26
|
+
* insufficient, that is the verifier's judgement to make, and the gateway will
|
|
27
|
+
* schedule another round against `maxIterations`. A worker never extends its
|
|
28
|
+
* own budget.
|
|
29
|
+
*
|
|
30
|
+
* The upper bound on work per task is therefore fixed and knowable:
|
|
31
|
+
* 2 model calls and `min(remainingToolCalls, MAX_TOOL_CALLS_PER_TASK)` tool
|
|
32
|
+
* calls.
|
|
33
|
+
*/
|
|
34
|
+
/** Hard ceiling on tool calls in a single task, independent of run budget. */
|
|
35
|
+
export declare const MAX_TOOL_CALLS_PER_TASK = 8;
|
|
36
|
+
/** Model calls per task: one to select tools, one to summarize results. */
|
|
37
|
+
export declare const MAX_MODEL_CALLS_PER_TASK = 2;
|
|
38
|
+
export interface LocalGatewayTaskRunnerOptions {
|
|
39
|
+
provider: Provider;
|
|
40
|
+
registry: ToolRegistry;
|
|
41
|
+
toolContext: ToolContext;
|
|
42
|
+
maxTokens?: number;
|
|
43
|
+
temperature?: number;
|
|
44
|
+
/** Observability hook; see `GatewayTracer`. */
|
|
45
|
+
onEvent?: (event: LocalGatewayTaskRunnerEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
export type LocalGatewayTaskRunnerEvent = {
|
|
48
|
+
type: "task_start";
|
|
49
|
+
taskId: string;
|
|
50
|
+
workerRole: string;
|
|
51
|
+
allowedTools: string[];
|
|
52
|
+
} | {
|
|
53
|
+
type: "tool_call";
|
|
54
|
+
taskId: string;
|
|
55
|
+
tool: string;
|
|
56
|
+
args: unknown;
|
|
57
|
+
} | {
|
|
58
|
+
type: "tool_result";
|
|
59
|
+
taskId: string;
|
|
60
|
+
tool: string;
|
|
61
|
+
ok: boolean;
|
|
62
|
+
latencyMs: number;
|
|
63
|
+
errorCode?: string;
|
|
64
|
+
} | {
|
|
65
|
+
type: "task_end";
|
|
66
|
+
taskId: string;
|
|
67
|
+
status: "succeeded" | "failed";
|
|
68
|
+
toolCallCount: number;
|
|
69
|
+
modelCallCount: number;
|
|
70
|
+
durationMs: number;
|
|
71
|
+
};
|
|
72
|
+
export declare class LocalGatewayTaskRunner implements CodaliGatewayWorkerTaskRunner {
|
|
73
|
+
private readonly options;
|
|
74
|
+
constructor(options: LocalGatewayTaskRunnerOptions);
|
|
75
|
+
run(input: CodaliGatewayWorkerTaskRunInput): Promise<CodaliGatewayWorkerTaskRunResult>;
|
|
76
|
+
}
|
|
77
|
+
export declare const createLocalGatewayTaskRunner: (options: LocalGatewayTaskRunnerOptions) => LocalGatewayTaskRunner;
|
|
78
|
+
export declare const isRecordValue: (value: unknown) => value is Record<string, unknown>;
|
|
79
|
+
//# sourceMappingURL=LocalGatewayTaskRunner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalGatewayTaskRunner.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayTaskRunner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAEV,+BAA+B,EAC/B,gCAAgC,EAChC,6BAA6B,EAE9B,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,2EAA2E;AAC3E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAe1C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAClE;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AA6DN,qBAAa,sBAAuB,YAAW,6BAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,6BAA6B;IAE7D,GAAG,CACP,KAAK,EAAE,+BAA+B,GACrC,OAAO,CAAC,gCAAgC,CAAC;CAqT7C;AAED,eAAO,MAAM,4BAA4B,GACvC,SAAS,6BAA6B,KACrC,sBAA6D,CAAC;AAEjE,eAAO,MAAM,aAAa,UA3XD,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CA2X7B,CAAC"}
|