archbyte 0.1.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/README.md +282 -0
- package/bin/archbyte.js +213 -0
- package/dist/agents/core/component-detector.d.ts +2 -0
- package/dist/agents/core/component-detector.js +57 -0
- package/dist/agents/core/connection-mapper.d.ts +2 -0
- package/dist/agents/core/connection-mapper.js +77 -0
- package/dist/agents/core/doc-parser.d.ts +2 -0
- package/dist/agents/core/doc-parser.js +64 -0
- package/dist/agents/core/env-detector.d.ts +2 -0
- package/dist/agents/core/env-detector.js +51 -0
- package/dist/agents/core/event-detector.d.ts +2 -0
- package/dist/agents/core/event-detector.js +59 -0
- package/dist/agents/core/infra-analyzer.d.ts +2 -0
- package/dist/agents/core/infra-analyzer.js +72 -0
- package/dist/agents/core/structure-scanner.d.ts +2 -0
- package/dist/agents/core/structure-scanner.js +55 -0
- package/dist/agents/core/validator.d.ts +2 -0
- package/dist/agents/core/validator.js +74 -0
- package/dist/agents/index.d.ts +24 -0
- package/dist/agents/index.js +73 -0
- package/dist/agents/llm/index.d.ts +8 -0
- package/dist/agents/llm/index.js +185 -0
- package/dist/agents/llm/prompt-builder.d.ts +3 -0
- package/dist/agents/llm/prompt-builder.js +251 -0
- package/dist/agents/llm/response-parser.d.ts +6 -0
- package/dist/agents/llm/response-parser.js +174 -0
- package/dist/agents/llm/types.d.ts +31 -0
- package/dist/agents/llm/types.js +2 -0
- package/dist/agents/pipeline/agents/component-identifier.d.ts +3 -0
- package/dist/agents/pipeline/agents/component-identifier.js +102 -0
- package/dist/agents/pipeline/agents/connection-mapper.d.ts +3 -0
- package/dist/agents/pipeline/agents/connection-mapper.js +126 -0
- package/dist/agents/pipeline/agents/flow-detector.d.ts +3 -0
- package/dist/agents/pipeline/agents/flow-detector.js +101 -0
- package/dist/agents/pipeline/agents/service-describer.d.ts +3 -0
- package/dist/agents/pipeline/agents/service-describer.js +100 -0
- package/dist/agents/pipeline/agents/validator.d.ts +3 -0
- package/dist/agents/pipeline/agents/validator.js +102 -0
- package/dist/agents/pipeline/index.d.ts +13 -0
- package/dist/agents/pipeline/index.js +128 -0
- package/dist/agents/pipeline/merger.d.ts +7 -0
- package/dist/agents/pipeline/merger.js +212 -0
- package/dist/agents/pipeline/response-parser.d.ts +5 -0
- package/dist/agents/pipeline/response-parser.js +43 -0
- package/dist/agents/pipeline/types.d.ts +92 -0
- package/dist/agents/pipeline/types.js +3 -0
- package/dist/agents/prompt-data.d.ts +1 -0
- package/dist/agents/prompt-data.js +15 -0
- package/dist/agents/prompts-encode.d.ts +9 -0
- package/dist/agents/prompts-encode.js +26 -0
- package/dist/agents/prompts.d.ts +12 -0
- package/dist/agents/prompts.js +30 -0
- package/dist/agents/providers/anthropic.d.ts +10 -0
- package/dist/agents/providers/anthropic.js +117 -0
- package/dist/agents/providers/google.d.ts +10 -0
- package/dist/agents/providers/google.js +136 -0
- package/dist/agents/providers/ollama.d.ts +9 -0
- package/dist/agents/providers/ollama.js +162 -0
- package/dist/agents/providers/openai.d.ts +9 -0
- package/dist/agents/providers/openai.js +142 -0
- package/dist/agents/providers/router.d.ts +7 -0
- package/dist/agents/providers/router.js +55 -0
- package/dist/agents/runtime/orchestrator.d.ts +34 -0
- package/dist/agents/runtime/orchestrator.js +193 -0
- package/dist/agents/runtime/registry.d.ts +23 -0
- package/dist/agents/runtime/registry.js +56 -0
- package/dist/agents/runtime/types.d.ts +117 -0
- package/dist/agents/runtime/types.js +29 -0
- package/dist/agents/static/code-sampler.d.ts +3 -0
- package/dist/agents/static/code-sampler.js +153 -0
- package/dist/agents/static/component-detector.d.ts +3 -0
- package/dist/agents/static/component-detector.js +404 -0
- package/dist/agents/static/connection-mapper.d.ts +3 -0
- package/dist/agents/static/connection-mapper.js +280 -0
- package/dist/agents/static/doc-parser.d.ts +3 -0
- package/dist/agents/static/doc-parser.js +358 -0
- package/dist/agents/static/env-detector.d.ts +3 -0
- package/dist/agents/static/env-detector.js +73 -0
- package/dist/agents/static/event-detector.d.ts +3 -0
- package/dist/agents/static/event-detector.js +70 -0
- package/dist/agents/static/file-tree-collector.d.ts +3 -0
- package/dist/agents/static/file-tree-collector.js +51 -0
- package/dist/agents/static/index.d.ts +19 -0
- package/dist/agents/static/index.js +307 -0
- package/dist/agents/static/infra-analyzer.d.ts +3 -0
- package/dist/agents/static/infra-analyzer.js +208 -0
- package/dist/agents/static/structure-scanner.d.ts +3 -0
- package/dist/agents/static/structure-scanner.js +195 -0
- package/dist/agents/static/types.d.ts +165 -0
- package/dist/agents/static/types.js +2 -0
- package/dist/agents/static/utils.d.ts +21 -0
- package/dist/agents/static/utils.js +146 -0
- package/dist/agents/static/validator.d.ts +2 -0
- package/dist/agents/static/validator.js +75 -0
- package/dist/agents/tools/claude-code.d.ts +38 -0
- package/dist/agents/tools/claude-code.js +129 -0
- package/dist/agents/tools/local-fs.d.ts +12 -0
- package/dist/agents/tools/local-fs.js +112 -0
- package/dist/agents/tools/tool-definitions.d.ts +6 -0
- package/dist/agents/tools/tool-definitions.js +66 -0
- package/dist/cli/analyze.d.ts +27 -0
- package/dist/cli/analyze.js +586 -0
- package/dist/cli/auth.d.ts +46 -0
- package/dist/cli/auth.js +397 -0
- package/dist/cli/config.d.ts +11 -0
- package/dist/cli/config.js +177 -0
- package/dist/cli/diff.d.ts +10 -0
- package/dist/cli/diff.js +144 -0
- package/dist/cli/export.d.ts +10 -0
- package/dist/cli/export.js +321 -0
- package/dist/cli/gate.d.ts +13 -0
- package/dist/cli/gate.js +131 -0
- package/dist/cli/generate.d.ts +10 -0
- package/dist/cli/generate.js +213 -0
- package/dist/cli/license-gate.d.ts +27 -0
- package/dist/cli/license-gate.js +121 -0
- package/dist/cli/patrol.d.ts +15 -0
- package/dist/cli/patrol.js +212 -0
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.js +24 -0
- package/dist/cli/serve.d.ts +9 -0
- package/dist/cli/serve.js +65 -0
- package/dist/cli/setup.d.ts +1 -0
- package/dist/cli/setup.js +233 -0
- package/dist/cli/shared.d.ts +68 -0
- package/dist/cli/shared.js +275 -0
- package/dist/cli/stats.d.ts +9 -0
- package/dist/cli/stats.js +158 -0
- package/dist/cli/ui.d.ts +18 -0
- package/dist/cli/ui.js +144 -0
- package/dist/cli/validate.d.ts +54 -0
- package/dist/cli/validate.js +315 -0
- package/dist/cli/workflow.d.ts +10 -0
- package/dist/cli/workflow.js +594 -0
- package/dist/server/src/generator/index.d.ts +123 -0
- package/dist/server/src/generator/index.js +254 -0
- package/dist/server/src/index.d.ts +8 -0
- package/dist/server/src/index.js +1311 -0
- package/package.json +62 -0
- package/ui/dist/assets/index-B66Til39.js +70 -0
- package/ui/dist/assets/index-BE2OWbzu.css +1 -0
- package/ui/dist/index.html +14 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { resolveModel } from "./types.js";
|
|
2
|
+
import { AGENT_TOOLS } from "../tools/tool-definitions.js";
|
|
3
|
+
/**
|
|
4
|
+
* Agent Orchestrator — runs the multi-agent analysis pipeline.
|
|
5
|
+
*
|
|
6
|
+
* Phase 1 (parallel): structure-scanner, doc-parser, infra-analyzer,
|
|
7
|
+
* component-detector, event-detector, env-detector
|
|
8
|
+
* Phase 2 (sequential): connection-mapper (needs Phase 1 results)
|
|
9
|
+
* Phase 3 (sequential): validator (needs Phase 2 results)
|
|
10
|
+
*/
|
|
11
|
+
export class Orchestrator {
|
|
12
|
+
agents = [];
|
|
13
|
+
provider;
|
|
14
|
+
tools;
|
|
15
|
+
projectRoot;
|
|
16
|
+
config;
|
|
17
|
+
license;
|
|
18
|
+
constructor(opts) {
|
|
19
|
+
this.provider = opts.provider;
|
|
20
|
+
this.tools = opts.tools;
|
|
21
|
+
this.projectRoot = opts.projectRoot;
|
|
22
|
+
this.config = opts.config;
|
|
23
|
+
this.license = opts.license;
|
|
24
|
+
}
|
|
25
|
+
register(agent) {
|
|
26
|
+
this.agents.push(agent);
|
|
27
|
+
}
|
|
28
|
+
registerAll(agents) {
|
|
29
|
+
for (const agent of agents) {
|
|
30
|
+
this.register(agent);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async run(onProgress) {
|
|
34
|
+
const start = Date.now();
|
|
35
|
+
const results = [];
|
|
36
|
+
const errors = [];
|
|
37
|
+
// Filter agents by license tier
|
|
38
|
+
const allowed = this.agents.filter((a) => this.isAllowed(a));
|
|
39
|
+
const blocked = this.agents.filter((a) => !this.isAllowed(a));
|
|
40
|
+
if (blocked.length > 0) {
|
|
41
|
+
onProgress?.(`Skipping ${blocked.length} premium agent(s) — upgrade to Pro to unlock`);
|
|
42
|
+
}
|
|
43
|
+
// Split into phases
|
|
44
|
+
const parallel = allowed.filter((a) => a.phase === "parallel");
|
|
45
|
+
const sequential = allowed.filter((a) => a.phase === "sequential");
|
|
46
|
+
// Phase 1: Run parallel agents
|
|
47
|
+
onProgress?.(`Running ${parallel.length} agents in parallel...`);
|
|
48
|
+
const parallelResults = await Promise.allSettled(parallel.map((agent) => this.runAgent(agent, {}, onProgress)));
|
|
49
|
+
const resultMap = {};
|
|
50
|
+
for (let i = 0; i < parallel.length; i++) {
|
|
51
|
+
const result = parallelResults[i];
|
|
52
|
+
if (result.status === "fulfilled") {
|
|
53
|
+
results.push(result.value);
|
|
54
|
+
resultMap[parallel[i].id] = result.value;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const errorMsg = result.reason instanceof Error
|
|
58
|
+
? result.reason.message
|
|
59
|
+
: String(result.reason);
|
|
60
|
+
errors.push({ agentId: parallel[i].id, error: errorMsg });
|
|
61
|
+
onProgress?.(`Agent ${parallel[i].name} failed: ${errorMsg}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Phase 2+3: Run sequential agents with prior results
|
|
65
|
+
for (const agent of sequential) {
|
|
66
|
+
onProgress?.(`Running ${agent.name}...`);
|
|
67
|
+
try {
|
|
68
|
+
const result = await this.runAgent(agent, resultMap, onProgress);
|
|
69
|
+
results.push(result);
|
|
70
|
+
resultMap[agent.id] = result;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
errors.push({ agentId: agent.id, error: errorMsg });
|
|
75
|
+
onProgress?.(`Agent ${agent.name} failed: ${errorMsg}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
agents: results,
|
|
80
|
+
totalDuration: Date.now() - start,
|
|
81
|
+
success: errors.length === 0,
|
|
82
|
+
errors,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
isAllowed(agent) {
|
|
86
|
+
if (agent.tier === "free")
|
|
87
|
+
return true;
|
|
88
|
+
if (agent.tier === "premium" && this.license.tier === "premium")
|
|
89
|
+
return true;
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
async runAgent(agent, priorResults, onProgress) {
|
|
93
|
+
const model = resolveModel(this.config.provider, agent.modelTier, this.config.modelOverrides);
|
|
94
|
+
// Create a model-routed provider wrapper
|
|
95
|
+
const routedProvider = {
|
|
96
|
+
name: this.provider.name,
|
|
97
|
+
chat: (params) => this.provider.chat({ ...params, model: params.model ?? model }),
|
|
98
|
+
stream: (params) => this.provider.stream({ ...params, model: params.model ?? model }),
|
|
99
|
+
};
|
|
100
|
+
const context = {
|
|
101
|
+
llm: routedProvider,
|
|
102
|
+
tools: this.tools,
|
|
103
|
+
projectRoot: this.projectRoot,
|
|
104
|
+
priorResults: Object.keys(priorResults).length > 0 ? priorResults : undefined,
|
|
105
|
+
onProgress,
|
|
106
|
+
};
|
|
107
|
+
onProgress?.(`Starting ${agent.name}...`);
|
|
108
|
+
const start = Date.now();
|
|
109
|
+
const result = await agent.run(context);
|
|
110
|
+
result.duration = Date.now() - start;
|
|
111
|
+
onProgress?.(`${agent.name} completed in ${result.duration}ms`);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Execute a tool_use loop for an agent.
|
|
117
|
+
* This is the core pattern: send prompt → get tool calls → execute tools → send results → repeat.
|
|
118
|
+
*/
|
|
119
|
+
export async function executeToolLoop(context, systemPrompt, userMessage, maxIterations = 20) {
|
|
120
|
+
const messages = [{ role: "user", content: userMessage }];
|
|
121
|
+
for (let i = 0; i < maxIterations; i++) {
|
|
122
|
+
const response = await context.llm.chat({
|
|
123
|
+
system: systemPrompt,
|
|
124
|
+
messages,
|
|
125
|
+
tools: AGENT_TOOLS,
|
|
126
|
+
maxTokens: 8192,
|
|
127
|
+
});
|
|
128
|
+
// Collect text output
|
|
129
|
+
const textParts = response.content
|
|
130
|
+
.filter((b) => b.type === "text")
|
|
131
|
+
.map((b) => b.text ?? "");
|
|
132
|
+
// Check for tool calls
|
|
133
|
+
const toolCalls = response.content.filter((b) => b.type === "tool_use");
|
|
134
|
+
if (toolCalls.length === 0 || response.stopReason !== "tool_use") {
|
|
135
|
+
// No more tool calls — return final text
|
|
136
|
+
return textParts.join("\n");
|
|
137
|
+
}
|
|
138
|
+
// Add assistant response to messages
|
|
139
|
+
messages.push({ role: "assistant", content: response.content });
|
|
140
|
+
// Execute each tool call and add results
|
|
141
|
+
const toolResults = [];
|
|
142
|
+
for (const tc of toolCalls) {
|
|
143
|
+
const result = await executeTool(context.tools, tc.name, tc.input);
|
|
144
|
+
context.onProgress?.(`Tool ${tc.name}(${summarizeInput(tc.input)})`);
|
|
145
|
+
toolResults.push({
|
|
146
|
+
type: "tool_result",
|
|
147
|
+
tool_use_id: tc.id,
|
|
148
|
+
content: result,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
messages.push({ role: "user", content: toolResults });
|
|
152
|
+
}
|
|
153
|
+
throw new Error("Agent exceeded maximum tool iterations");
|
|
154
|
+
}
|
|
155
|
+
async function executeTool(tools, name, input) {
|
|
156
|
+
try {
|
|
157
|
+
switch (name) {
|
|
158
|
+
case "read_file": {
|
|
159
|
+
const content = await tools.readFile(input.path);
|
|
160
|
+
// Truncate very large files
|
|
161
|
+
if (content.length > 50000) {
|
|
162
|
+
return content.slice(0, 50000) + "\n\n[... truncated, file too large]";
|
|
163
|
+
}
|
|
164
|
+
return content;
|
|
165
|
+
}
|
|
166
|
+
case "glob": {
|
|
167
|
+
const files = await tools.glob(input.pattern);
|
|
168
|
+
return files.join("\n") || "No files found";
|
|
169
|
+
}
|
|
170
|
+
case "grep": {
|
|
171
|
+
const results = await tools.grep(input.pattern, input.path);
|
|
172
|
+
return (results.map((r) => `${r.file}:${r.line}: ${r.content}`).join("\n") ||
|
|
173
|
+
"No matches found");
|
|
174
|
+
}
|
|
175
|
+
case "list_dir": {
|
|
176
|
+
const entries = await tools.listDir(input.path);
|
|
177
|
+
return entries
|
|
178
|
+
.map((e) => `${e.type === "directory" ? "d" : "f"} ${e.name}${e.size ? ` (${e.size}B)` : ""}`)
|
|
179
|
+
.join("\n") || "Empty directory";
|
|
180
|
+
}
|
|
181
|
+
default:
|
|
182
|
+
return `Unknown tool: ${name}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
return `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function summarizeInput(input) {
|
|
190
|
+
const val = input.path ?? input.pattern ?? "";
|
|
191
|
+
const s = String(val);
|
|
192
|
+
return s.length > 40 ? s.slice(0, 40) + "..." : s;
|
|
193
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ArchByteAgent, AgentTier } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Agent Registry — discovers and manages available agents.
|
|
4
|
+
* Handles tier gating (free vs pro vs enterprise).
|
|
5
|
+
*/
|
|
6
|
+
export declare class AgentRegistry {
|
|
7
|
+
private agents;
|
|
8
|
+
register(agent: ArchByteAgent): void;
|
|
9
|
+
get(id: string): ArchByteAgent | undefined;
|
|
10
|
+
getAll(): ArchByteAgent[];
|
|
11
|
+
getByTier(tier: AgentTier): ArchByteAgent[];
|
|
12
|
+
/**
|
|
13
|
+
* Get agents that the given license tier can access.
|
|
14
|
+
* free → only free agents
|
|
15
|
+
* premium → all agents (free + premium)
|
|
16
|
+
*/
|
|
17
|
+
getAccessible(licenseTier: AgentTier): ArchByteAgent[];
|
|
18
|
+
getCoreAgents(): ArchByteAgent[];
|
|
19
|
+
getPremiumAgents(): ArchByteAgent[];
|
|
20
|
+
getParallelAgents(licenseTier: AgentTier): ArchByteAgent[];
|
|
21
|
+
getSequentialAgents(licenseTier: AgentTier): ArchByteAgent[];
|
|
22
|
+
}
|
|
23
|
+
export declare function getRegistry(): AgentRegistry;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Registry — discovers and manages available agents.
|
|
3
|
+
* Handles tier gating (free vs pro vs enterprise).
|
|
4
|
+
*/
|
|
5
|
+
export class AgentRegistry {
|
|
6
|
+
agents = new Map();
|
|
7
|
+
register(agent) {
|
|
8
|
+
if (this.agents.has(agent.id)) {
|
|
9
|
+
throw new Error(`Agent already registered: ${agent.id}`);
|
|
10
|
+
}
|
|
11
|
+
this.agents.set(agent.id, agent);
|
|
12
|
+
}
|
|
13
|
+
get(id) {
|
|
14
|
+
return this.agents.get(id);
|
|
15
|
+
}
|
|
16
|
+
getAll() {
|
|
17
|
+
return Array.from(this.agents.values());
|
|
18
|
+
}
|
|
19
|
+
getByTier(tier) {
|
|
20
|
+
return this.getAll().filter((a) => a.tier === tier);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get agents that the given license tier can access.
|
|
24
|
+
* free → only free agents
|
|
25
|
+
* premium → all agents (free + premium)
|
|
26
|
+
*/
|
|
27
|
+
getAccessible(licenseTier) {
|
|
28
|
+
return this.getAll().filter((a) => {
|
|
29
|
+
if (a.tier === "free")
|
|
30
|
+
return true;
|
|
31
|
+
if (a.tier === "premium" && licenseTier === "premium")
|
|
32
|
+
return true;
|
|
33
|
+
return false;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
getCoreAgents() {
|
|
37
|
+
return this.getByTier("free");
|
|
38
|
+
}
|
|
39
|
+
getPremiumAgents() {
|
|
40
|
+
return this.getByTier("premium");
|
|
41
|
+
}
|
|
42
|
+
getParallelAgents(licenseTier) {
|
|
43
|
+
return this.getAccessible(licenseTier).filter((a) => a.phase === "parallel");
|
|
44
|
+
}
|
|
45
|
+
getSequentialAgents(licenseTier) {
|
|
46
|
+
return this.getAccessible(licenseTier).filter((a) => a.phase === "sequential");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Singleton registry
|
|
50
|
+
let globalRegistry = null;
|
|
51
|
+
export function getRegistry() {
|
|
52
|
+
if (!globalRegistry) {
|
|
53
|
+
globalRegistry = new AgentRegistry();
|
|
54
|
+
}
|
|
55
|
+
return globalRegistry;
|
|
56
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
export interface Message {
|
|
2
|
+
role: "user" | "assistant";
|
|
3
|
+
content: string | ContentBlock[];
|
|
4
|
+
}
|
|
5
|
+
export interface ContentBlock {
|
|
6
|
+
type: "text" | "tool_use" | "tool_result";
|
|
7
|
+
text?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
input?: Record<string, unknown>;
|
|
11
|
+
tool_use_id?: string;
|
|
12
|
+
content?: string;
|
|
13
|
+
is_error?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ToolDefinition {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
input_schema: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface ChatParams {
|
|
21
|
+
model?: string;
|
|
22
|
+
system: string;
|
|
23
|
+
messages: Message[];
|
|
24
|
+
tools?: ToolDefinition[];
|
|
25
|
+
maxTokens?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface LLMResponse {
|
|
28
|
+
content: ContentBlock[];
|
|
29
|
+
stopReason: "end_turn" | "tool_use" | "max_tokens" | "stop_sequence";
|
|
30
|
+
usage: {
|
|
31
|
+
inputTokens: number;
|
|
32
|
+
outputTokens: number;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export interface LLMChunk {
|
|
36
|
+
type: "text" | "tool_use_start" | "tool_use_input" | "done";
|
|
37
|
+
text?: string;
|
|
38
|
+
toolName?: string;
|
|
39
|
+
toolId?: string;
|
|
40
|
+
input?: string;
|
|
41
|
+
}
|
|
42
|
+
export type ModelTier = "fast" | "standard" | "advanced";
|
|
43
|
+
export interface LLMProvider {
|
|
44
|
+
name: string;
|
|
45
|
+
chat(params: ChatParams): Promise<LLMResponse>;
|
|
46
|
+
stream(params: ChatParams): AsyncIterable<LLMChunk>;
|
|
47
|
+
}
|
|
48
|
+
export interface GrepResult {
|
|
49
|
+
file: string;
|
|
50
|
+
line: number;
|
|
51
|
+
content: string;
|
|
52
|
+
}
|
|
53
|
+
export interface DirEntry {
|
|
54
|
+
name: string;
|
|
55
|
+
type: "file" | "directory";
|
|
56
|
+
size?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface ToolBackend {
|
|
59
|
+
readFile(path: string): Promise<string>;
|
|
60
|
+
glob(pattern: string, cwd?: string): Promise<string[]>;
|
|
61
|
+
grep(pattern: string, path?: string): Promise<GrepResult[]>;
|
|
62
|
+
listDir(path: string): Promise<DirEntry[]>;
|
|
63
|
+
}
|
|
64
|
+
export type AgentTier = "free" | "premium";
|
|
65
|
+
export type AgentPhase = "parallel" | "sequential";
|
|
66
|
+
export type ToolName = "read_file" | "glob" | "grep" | "list_dir";
|
|
67
|
+
export interface AgentContext {
|
|
68
|
+
llm: LLMProvider;
|
|
69
|
+
tools: ToolBackend;
|
|
70
|
+
projectRoot: string;
|
|
71
|
+
priorResults?: Record<string, AgentResult>;
|
|
72
|
+
onProgress?: (msg: string) => void;
|
|
73
|
+
}
|
|
74
|
+
export interface AgentResult {
|
|
75
|
+
agentId: string;
|
|
76
|
+
data: unknown;
|
|
77
|
+
confidence: number;
|
|
78
|
+
duration: number;
|
|
79
|
+
}
|
|
80
|
+
export interface ArchByteAgent {
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
description: string;
|
|
84
|
+
tier: AgentTier;
|
|
85
|
+
phase: AgentPhase;
|
|
86
|
+
modelTier: ModelTier;
|
|
87
|
+
systemPrompt: string;
|
|
88
|
+
requiredTools: ToolName[];
|
|
89
|
+
run(context: AgentContext): Promise<AgentResult>;
|
|
90
|
+
}
|
|
91
|
+
export interface License {
|
|
92
|
+
tier: AgentTier | "none";
|
|
93
|
+
userId: string;
|
|
94
|
+
email: string;
|
|
95
|
+
scansUsed: number;
|
|
96
|
+
scansAllowed: number;
|
|
97
|
+
expiresAt: string;
|
|
98
|
+
isValid: boolean;
|
|
99
|
+
}
|
|
100
|
+
export type ProviderName = "anthropic" | "openai" | "google" | "ollama";
|
|
101
|
+
export interface ArchByteConfig {
|
|
102
|
+
provider: ProviderName;
|
|
103
|
+
apiKey: string;
|
|
104
|
+
modelOverrides?: Partial<Record<ModelTier, string>>;
|
|
105
|
+
ollamaBaseUrl?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface PipelineResult {
|
|
108
|
+
agents: AgentResult[];
|
|
109
|
+
totalDuration: number;
|
|
110
|
+
success: boolean;
|
|
111
|
+
errors: Array<{
|
|
112
|
+
agentId: string;
|
|
113
|
+
error: string;
|
|
114
|
+
}>;
|
|
115
|
+
}
|
|
116
|
+
export declare const MODEL_MAP: Record<ProviderName, Record<ModelTier, string>>;
|
|
117
|
+
export declare function resolveModel(provider: ProviderName, tier: ModelTier, overrides?: Partial<Record<ModelTier, string>>): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// ArchByte Agent Framework — Core Types
|
|
2
|
+
// === Model Routing ===
|
|
3
|
+
export const MODEL_MAP = {
|
|
4
|
+
anthropic: {
|
|
5
|
+
fast: "claude-haiku-4-5-20251001",
|
|
6
|
+
standard: "claude-sonnet-4-5-20250929",
|
|
7
|
+
advanced: "claude-opus-4-6",
|
|
8
|
+
},
|
|
9
|
+
openai: {
|
|
10
|
+
fast: "gpt-4o-mini",
|
|
11
|
+
standard: "gpt-4o",
|
|
12
|
+
advanced: "o3",
|
|
13
|
+
},
|
|
14
|
+
google: {
|
|
15
|
+
fast: "gemini-2.0-flash",
|
|
16
|
+
standard: "gemini-2.5-pro",
|
|
17
|
+
advanced: "gemini-2.5-pro",
|
|
18
|
+
},
|
|
19
|
+
ollama: {
|
|
20
|
+
fast: "llama3.2",
|
|
21
|
+
standard: "llama3.3",
|
|
22
|
+
advanced: "llama3.3",
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export function resolveModel(provider, tier, overrides) {
|
|
26
|
+
if (overrides?.[tier])
|
|
27
|
+
return overrides[tier];
|
|
28
|
+
return MODEL_MAP[provider][tier];
|
|
29
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Static Analysis — Code Sampler
|
|
2
|
+
// Collects key file excerpts, import graph, and config files for LLM context
|
|
3
|
+
const MAX_EXCERPT_LINES = 80;
|
|
4
|
+
const MAX_IMPORT_GREP = 500;
|
|
5
|
+
const MAX_ROUTE_GREP = 100;
|
|
6
|
+
/** Config file names to look for at the project root and in workspace dirs */
|
|
7
|
+
const CONFIG_FILES = [
|
|
8
|
+
"package.json",
|
|
9
|
+
"docker-compose.yml", "docker-compose.yaml", "compose.yml", "compose.yaml",
|
|
10
|
+
"Cargo.toml", "go.mod", "pyproject.toml", "requirements.txt",
|
|
11
|
+
"Makefile", "Dockerfile",
|
|
12
|
+
"tsconfig.json", "vite.config.ts", "vite.config.js",
|
|
13
|
+
"next.config.js", "next.config.ts", "next.config.mjs",
|
|
14
|
+
"nest-cli.json", "angular.json",
|
|
15
|
+
];
|
|
16
|
+
/** Common entry point filenames */
|
|
17
|
+
const ENTRY_POINTS = [
|
|
18
|
+
"src/index.ts", "src/index.js", "src/main.ts", "src/main.js",
|
|
19
|
+
"src/app.ts", "src/app.js", "src/server.ts", "src/server.js",
|
|
20
|
+
"index.ts", "index.js", "main.ts", "main.js",
|
|
21
|
+
"app.ts", "app.js", "server.ts", "server.js",
|
|
22
|
+
"main.py", "app.py", "manage.py",
|
|
23
|
+
"main.go", "cmd/main.go", "cmd/server/main.go",
|
|
24
|
+
"src/main.rs", "src/lib.rs",
|
|
25
|
+
];
|
|
26
|
+
export async function collectCodeSamples(tk) {
|
|
27
|
+
const samples = [];
|
|
28
|
+
const configFiles = [];
|
|
29
|
+
const importMap = {};
|
|
30
|
+
// 1. Find workspace directories (dirs with a build config)
|
|
31
|
+
const rootEntries = await tk.listDir(".");
|
|
32
|
+
const topDirs = rootEntries
|
|
33
|
+
.filter((e) => e.type === "directory" && !e.name.startsWith(".") && !isVendored(e.name))
|
|
34
|
+
.map((e) => e.name);
|
|
35
|
+
// 2. Collect config files at root level
|
|
36
|
+
await collectConfigs(tk, ".", configFiles);
|
|
37
|
+
// 3. Collect config files in top-level directories
|
|
38
|
+
const configPromises = topDirs.map((dir) => collectConfigs(tk, dir, configFiles));
|
|
39
|
+
await Promise.all(configPromises);
|
|
40
|
+
// Also check for sub-workspace dirs (e.g., apps/web, packages/core)
|
|
41
|
+
const subDirChecks = ["apps", "packages", "services", "libs", "modules", "crates"];
|
|
42
|
+
for (const parent of subDirChecks) {
|
|
43
|
+
if (!topDirs.includes(parent))
|
|
44
|
+
continue;
|
|
45
|
+
const subEntries = await tk.listDir(parent);
|
|
46
|
+
const subDirs = subEntries
|
|
47
|
+
.filter((e) => e.type === "directory" && !e.name.startsWith("."))
|
|
48
|
+
.map((e) => `${parent}/${e.name}`);
|
|
49
|
+
await Promise.all(subDirs.map((dir) => collectConfigs(tk, dir, configFiles)));
|
|
50
|
+
}
|
|
51
|
+
// 4. Collect entry point excerpts for dirs that have configs
|
|
52
|
+
const dirsWithConfigs = new Set();
|
|
53
|
+
for (const cf of configFiles) {
|
|
54
|
+
const dir = cf.path.includes("/") ? cf.path.substring(0, cf.path.lastIndexOf("/")) : ".";
|
|
55
|
+
dirsWithConfigs.add(dir);
|
|
56
|
+
}
|
|
57
|
+
for (const dir of dirsWithConfigs) {
|
|
58
|
+
await collectEntryPoint(tk, dir, samples);
|
|
59
|
+
}
|
|
60
|
+
// 5. Build import map from grep
|
|
61
|
+
try {
|
|
62
|
+
const importResults = await tk.grepFiles("import\\s.*from\\s|require\\(");
|
|
63
|
+
for (const r of importResults.slice(0, MAX_IMPORT_GREP)) {
|
|
64
|
+
if (isVendoredPath(r.file))
|
|
65
|
+
continue;
|
|
66
|
+
const imported = extractImportPath(r.content);
|
|
67
|
+
if (imported) {
|
|
68
|
+
if (!importMap[r.file])
|
|
69
|
+
importMap[r.file] = [];
|
|
70
|
+
importMap[r.file].push(imported);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// grep failed, skip import map
|
|
76
|
+
}
|
|
77
|
+
// 6. Collect route file samples
|
|
78
|
+
try {
|
|
79
|
+
const routeResults = await tk.grepFiles("app\\.(get|post|put|delete|patch|use)\\(|router\\.|@(Get|Post|Put|Delete|Patch)\\(|@app\\.route");
|
|
80
|
+
const routeFiles = new Set();
|
|
81
|
+
for (const r of routeResults.slice(0, MAX_ROUTE_GREP)) {
|
|
82
|
+
if (isVendoredPath(r.file))
|
|
83
|
+
continue;
|
|
84
|
+
routeFiles.add(r.file);
|
|
85
|
+
}
|
|
86
|
+
// Read first 80 lines of each unique route file (up to 10)
|
|
87
|
+
let routeCount = 0;
|
|
88
|
+
for (const filePath of routeFiles) {
|
|
89
|
+
if (routeCount >= 10)
|
|
90
|
+
break;
|
|
91
|
+
if (samples.some((s) => s.path === filePath))
|
|
92
|
+
continue;
|
|
93
|
+
const content = await tk.readFileSafe(filePath);
|
|
94
|
+
if (!content)
|
|
95
|
+
continue;
|
|
96
|
+
const excerpt = content.split("\n").slice(0, MAX_EXCERPT_LINES).join("\n");
|
|
97
|
+
samples.push({ path: filePath, excerpt, category: "route-file" });
|
|
98
|
+
routeCount++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// grep failed, skip route files
|
|
103
|
+
}
|
|
104
|
+
return { samples, importMap, configFiles };
|
|
105
|
+
}
|
|
106
|
+
async function collectConfigs(tk, dir, configFiles) {
|
|
107
|
+
for (const name of CONFIG_FILES) {
|
|
108
|
+
const filePath = dir === "." ? name : `${dir}/${name}`;
|
|
109
|
+
const content = await tk.readFileSafe(filePath);
|
|
110
|
+
if (content) {
|
|
111
|
+
// Cap config content at 5000 chars to avoid blowing context
|
|
112
|
+
configFiles.push({
|
|
113
|
+
path: filePath,
|
|
114
|
+
content: content.length > 5000 ? content.slice(0, 5000) + "\n... (truncated)" : content,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function collectEntryPoint(tk, dir, samples) {
|
|
120
|
+
for (const ep of ENTRY_POINTS) {
|
|
121
|
+
const filePath = dir === "." ? ep : `${dir}/${ep}`;
|
|
122
|
+
if (samples.some((s) => s.path === filePath))
|
|
123
|
+
continue;
|
|
124
|
+
const content = await tk.readFileSafe(filePath);
|
|
125
|
+
if (content) {
|
|
126
|
+
const excerpt = content.split("\n").slice(0, MAX_EXCERPT_LINES).join("\n");
|
|
127
|
+
samples.push({ path: filePath, excerpt, category: "entry-point" });
|
|
128
|
+
return; // one entry point per dir is enough
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
function extractImportPath(line) {
|
|
133
|
+
// ES import: import ... from "path"
|
|
134
|
+
const esMatch = line.match(/from\s+["']([^"']+)["']/);
|
|
135
|
+
if (esMatch)
|
|
136
|
+
return esMatch[1];
|
|
137
|
+
// CommonJS: require("path")
|
|
138
|
+
const cjsMatch = line.match(/require\(\s*["']([^"']+)["']\s*\)/);
|
|
139
|
+
if (cjsMatch)
|
|
140
|
+
return cjsMatch[1];
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
const VENDORED = new Set([
|
|
144
|
+
"node_modules", "dist", "build", ".git", "venv", "__pycache__",
|
|
145
|
+
"target", "coverage", "vendor", ".next", ".nuxt",
|
|
146
|
+
]);
|
|
147
|
+
function isVendored(name) {
|
|
148
|
+
return VENDORED.has(name);
|
|
149
|
+
}
|
|
150
|
+
function isVendoredPath(filePath) {
|
|
151
|
+
const parts = filePath.split("/");
|
|
152
|
+
return parts.some((p) => VENDORED.has(p));
|
|
153
|
+
}
|