lobster-cli 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 +389 -0
- package/dist/agent/core.js +1013 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.js +1027 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/brain/index.js +60 -0
- package/dist/brain/index.js.map +1 -0
- package/dist/browser/dom/index.js +1096 -0
- package/dist/browser/dom/index.js.map +1 -0
- package/dist/browser/index.js +2034 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/manager.js +86 -0
- package/dist/browser/manager.js.map +1 -0
- package/dist/browser/page-adapter.js +1345 -0
- package/dist/browser/page-adapter.js.map +1 -0
- package/dist/cascade/index.js +138 -0
- package/dist/cascade/index.js.map +1 -0
- package/dist/config/index.js +110 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/schema.js +66 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/discover/index.js +545 -0
- package/dist/discover/index.js.map +1 -0
- package/dist/index.js +5529 -0
- package/dist/index.js.map +1 -0
- package/dist/lib.js +4206 -0
- package/dist/lib.js.map +1 -0
- package/dist/llm/client.js +379 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/index.js +397 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/openai-client.js +214 -0
- package/dist/llm/openai-client.js.map +1 -0
- package/dist/output/index.js +93 -0
- package/dist/output/index.js.map +1 -0
- package/dist/pipeline/index.js +802 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/router/decision.js +80 -0
- package/dist/router/decision.js.map +1 -0
- package/dist/router/index.js +3443 -0
- package/dist/router/index.js.map +1 -0
- package/dist/types/index.js +23 -0
- package/dist/types/index.js.map +1 -0
- package/logo.svg +11 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/llm/errors.ts","../../src/llm/openai-client.ts"],"sourcesContent":["export enum InvokeErrorType {\n NETWORK_ERROR = 'NETWORK_ERROR',\n AUTH_ERROR = 'AUTH_ERROR',\n RATE_LIMIT = 'RATE_LIMIT',\n SERVER_ERROR = 'SERVER_ERROR',\n CONTEXT_LENGTH = 'CONTEXT_LENGTH',\n CONTENT_FILTER = 'CONTENT_FILTER',\n NO_TOOL_CALL = 'NO_TOOL_CALL',\n INVALID_TOOL_ARGS = 'INVALID_TOOL_ARGS',\n TOOL_EXECUTION_ERROR = 'TOOL_EXECUTION_ERROR',\n UNKNOWN = 'UNKNOWN',\n}\n\nexport class InvokeError extends Error {\n type: InvokeErrorType;\n retryable: boolean;\n rawError?: unknown;\n rawResponse?: unknown;\n\n constructor(type: InvokeErrorType, message: string, opts?: { retryable?: boolean; rawError?: unknown; rawResponse?: unknown }) {\n super(message);\n this.name = 'InvokeError';\n this.type = type;\n this.retryable = opts?.retryable ?? isRetryable(type);\n this.rawError = opts?.rawError;\n this.rawResponse = opts?.rawResponse;\n }\n}\n\nfunction isRetryable(type: InvokeErrorType): boolean {\n switch (type) {\n case InvokeErrorType.NETWORK_ERROR:\n case InvokeErrorType.RATE_LIMIT:\n case InvokeErrorType.SERVER_ERROR:\n case InvokeErrorType.NO_TOOL_CALL:\n case InvokeErrorType.INVALID_TOOL_ARGS:\n case InvokeErrorType.TOOL_EXECUTION_ERROR:\n case InvokeErrorType.UNKNOWN:\n return true;\n case InvokeErrorType.AUTH_ERROR:\n case InvokeErrorType.CONTEXT_LENGTH:\n case InvokeErrorType.CONTENT_FILTER:\n return false;\n }\n}\n","import type { Message, ToolCall } from '../types/llm.js';\nimport type { LLMTool } from '../types/llm.js';\nimport { InvokeError, InvokeErrorType } from './errors.js';\nimport type { LLMProvider } from '../config/schema.js';\n\nexport interface OpenAIClientConfig {\n baseURL: string;\n model: string;\n apiKey?: string;\n temperature?: number;\n provider?: LLMProvider;\n}\n\nexport class OpenAIClient {\n private config: OpenAIClientConfig;\n\n constructor(config: OpenAIClientConfig) {\n this.config = config;\n }\n\n /**\n * Build auth headers based on the provider.\n * - OpenAI/Gemini/Ollama: Bearer token\n * - Anthropic: x-api-key header + anthropic-version\n */\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (!this.config.apiKey) return headers;\n\n if (this.config.provider === 'anthropic') {\n headers['x-api-key'] = this.config.apiKey;\n headers['anthropic-version'] = '2023-06-01';\n } else {\n headers['Authorization'] = `Bearer ${this.config.apiKey}`;\n }\n\n return headers;\n }\n\n /**\n * Build the request body based on provider.\n * Anthropic Messages API is different from OpenAI chat completions.\n */\n private buildBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n if (this.config.provider === 'anthropic') {\n return this.buildAnthropicBody(messages, tools, opts);\n }\n\n // OpenAI-compatible format (OpenAI, Gemini, Ollama all use this)\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (tools && tools.length > 0) {\n body.tools = tools;\n body.parallel_tool_calls = false;\n if (opts?.toolChoice) {\n body.tool_choice = typeof opts.toolChoice === 'string'\n ? opts.toolChoice\n : opts.toolChoice;\n }\n }\n\n return { url: `${this.config.baseURL}/chat/completions`, body };\n }\n\n /**\n * Build Anthropic Messages API request.\n * Converts OpenAI-style messages/tools to Anthropic format.\n */\n private buildAnthropicBody(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } },\n ): { url: string; body: Record<string, unknown> } {\n // Extract system message\n let system: string | undefined;\n const anthropicMessages: Record<string, unknown>[] = [];\n\n for (const msg of messages) {\n if (msg.role === 'system') {\n system = msg.content as string;\n } else {\n anthropicMessages.push({\n role: msg.role === 'assistant' ? 'assistant' : 'user',\n content: msg.content,\n });\n }\n }\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n messages: anthropicMessages,\n max_tokens: 4096,\n temperature: this.config.temperature ?? 0.1,\n };\n\n if (system) body.system = system;\n\n // Convert OpenAI tools format to Anthropic tools format\n if (tools && tools.length > 0) {\n body.tools = tools.map((t) => {\n const fn = (t as any).function;\n return {\n name: fn.name,\n description: fn.description,\n input_schema: fn.parameters,\n };\n });\n\n if (opts?.toolChoice) {\n if (typeof opts.toolChoice === 'string') {\n body.tool_choice = opts.toolChoice === 'required'\n ? { type: 'any' }\n : { type: opts.toolChoice };\n } else {\n body.tool_choice = { type: 'tool', name: opts.toolChoice.function.name };\n }\n }\n }\n\n return { url: `${this.config.baseURL}/messages`, body };\n }\n\n /**\n * Parse Anthropic response into our unified format.\n */\n private parseAnthropicResponse(json: Record<string, unknown>): {\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n } {\n const content = json.content as any[];\n if (!content || !Array.isArray(content)) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No content in Anthropic response', { rawResponse: json });\n }\n\n let textContent: string | undefined;\n const toolCalls: ToolCall[] = [];\n\n for (const block of content) {\n if (block.type === 'text') {\n textContent = block.text;\n } else if (block.type === 'tool_use') {\n toolCalls.push({\n id: block.id,\n type: 'function',\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n });\n }\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: toolCalls.length > 0 ? toolCalls : undefined,\n content: textContent,\n usage: usage ? {\n promptTokens: usage.input_tokens ?? 0,\n completionTokens: usage.output_tokens ?? 0,\n totalTokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),\n } : undefined,\n };\n }\n\n async chatCompletion(\n messages: Message[],\n tools?: LLMTool[],\n opts?: { toolChoice?: string | { type: 'function'; function: { name: string } } }\n ): Promise<{\n toolCalls?: ToolCall[];\n content?: string;\n usage?: { promptTokens: number; completionTokens: number; totalTokens: number };\n }> {\n const { url, body } = this.buildBody(messages, tools, opts);\n const headers = this.buildHeaders();\n\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n });\n } catch (err) {\n throw new InvokeError(InvokeErrorType.NETWORK_ERROR, `Network error: ${err}`, { rawError: err });\n }\n\n if (!response.ok) {\n const text = await response.text().catch(() => '');\n if (response.status === 401) {\n throw new InvokeError(InvokeErrorType.AUTH_ERROR, `Authentication failed: ${text}`, { retryable: false, rawResponse: text });\n }\n if (response.status === 429) {\n throw new InvokeError(InvokeErrorType.RATE_LIMIT, `Rate limited: ${text}`, { rawResponse: text });\n }\n if (response.status >= 500) {\n throw new InvokeError(InvokeErrorType.SERVER_ERROR, `Server error ${response.status}: ${text}`, { rawResponse: text });\n }\n throw new InvokeError(InvokeErrorType.UNKNOWN, `HTTP ${response.status}: ${text}`, { rawResponse: text });\n }\n\n const json = await response.json() as Record<string, unknown>;\n\n // Route to provider-specific parser\n if (this.config.provider === 'anthropic') {\n return this.parseAnthropicResponse(json);\n }\n\n // OpenAI-compatible response parsing (OpenAI, Gemini, Ollama)\n const choice = (json.choices as any[])?.[0];\n if (!choice) {\n throw new InvokeError(InvokeErrorType.UNKNOWN, 'No choices in response', { rawResponse: json });\n }\n\n const message = choice.message;\n const finishReason = choice.finish_reason;\n\n if (finishReason === 'content_filter') {\n throw new InvokeError(InvokeErrorType.CONTENT_FILTER, 'Content filtered', { retryable: false, rawResponse: json });\n }\n\n if (finishReason === 'length') {\n throw new InvokeError(InvokeErrorType.CONTEXT_LENGTH, 'Context length exceeded', { retryable: false, rawResponse: json });\n }\n\n const usage = json.usage as Record<string, number> | undefined;\n\n return {\n toolCalls: message.tool_calls as ToolCall[] | undefined,\n content: message.content as string | undefined,\n usage: usage ? {\n promptTokens: usage.prompt_tokens ?? 0,\n completionTokens: usage.completion_tokens ?? 0,\n totalTokens: usage.total_tokens ?? 0,\n } : undefined,\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/output/table.ts
|
|
2
|
+
import Table from "cli-table3";
|
|
3
|
+
function renderTable(data, columns) {
|
|
4
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
5
|
+
return typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
6
|
+
}
|
|
7
|
+
const cols = columns || Object.keys(data[0]);
|
|
8
|
+
const table = new Table({
|
|
9
|
+
head: cols,
|
|
10
|
+
style: { head: ["cyan"] },
|
|
11
|
+
wordWrap: true
|
|
12
|
+
});
|
|
13
|
+
for (const row of data) {
|
|
14
|
+
table.push(cols.map((col) => {
|
|
15
|
+
const val = row[col];
|
|
16
|
+
if (val === null || val === void 0) return "";
|
|
17
|
+
return String(val);
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
return table.toString();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/output/json.ts
|
|
24
|
+
function renderJson(data) {
|
|
25
|
+
return JSON.stringify(data, null, 2);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/output/markdown.ts
|
|
29
|
+
function renderMarkdown(data, columns) {
|
|
30
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
31
|
+
return typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
32
|
+
}
|
|
33
|
+
const cols = columns || Object.keys(data[0]);
|
|
34
|
+
const lines = [];
|
|
35
|
+
lines.push("| " + cols.join(" | ") + " |");
|
|
36
|
+
lines.push("| " + cols.map(() => "---").join(" | ") + " |");
|
|
37
|
+
for (const row of data) {
|
|
38
|
+
const vals = cols.map((col) => {
|
|
39
|
+
const val = row[col];
|
|
40
|
+
if (val === null || val === void 0) return "";
|
|
41
|
+
return String(val).replace(/\|/g, "\\|");
|
|
42
|
+
});
|
|
43
|
+
lines.push("| " + vals.join(" | ") + " |");
|
|
44
|
+
}
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/output/csv.ts
|
|
49
|
+
function renderCsv(data, columns) {
|
|
50
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
51
|
+
return typeof data === "string" ? data : JSON.stringify(data);
|
|
52
|
+
}
|
|
53
|
+
const cols = columns || Object.keys(data[0]);
|
|
54
|
+
const lines = [cols.join(",")];
|
|
55
|
+
for (const row of data) {
|
|
56
|
+
const vals = cols.map((col) => {
|
|
57
|
+
const val = row[col];
|
|
58
|
+
if (val === null || val === void 0) return "";
|
|
59
|
+
const str = String(val);
|
|
60
|
+
return str.includes(",") || str.includes('"') || str.includes("\n") ? `"${str.replace(/"/g, '""')}"` : str;
|
|
61
|
+
});
|
|
62
|
+
lines.push(vals.join(","));
|
|
63
|
+
}
|
|
64
|
+
return lines.join("\n");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/output/yaml.ts
|
|
68
|
+
import yaml from "js-yaml";
|
|
69
|
+
function renderYaml(data) {
|
|
70
|
+
return yaml.dump(data, { indent: 2, lineWidth: 120 });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/output/index.ts
|
|
74
|
+
function render(data, format, columns) {
|
|
75
|
+
switch (format) {
|
|
76
|
+
case "table":
|
|
77
|
+
return renderTable(data, columns);
|
|
78
|
+
case "json":
|
|
79
|
+
return renderJson(data);
|
|
80
|
+
case "markdown":
|
|
81
|
+
return renderMarkdown(data, columns);
|
|
82
|
+
case "csv":
|
|
83
|
+
return renderCsv(data, columns);
|
|
84
|
+
case "yaml":
|
|
85
|
+
return renderYaml(data);
|
|
86
|
+
default:
|
|
87
|
+
return renderJson(data);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
render
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/output/table.ts","../../src/output/json.ts","../../src/output/markdown.ts","../../src/output/csv.ts","../../src/output/yaml.ts","../../src/output/index.ts"],"sourcesContent":["import Table from 'cli-table3';\n\nexport function renderTable(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const table = new Table({\n head: cols,\n style: { head: ['cyan'] },\n wordWrap: true,\n });\n\n for (const row of data) {\n table.push(cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val);\n }));\n }\n\n return table.toString();\n}\n","export function renderJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n","export function renderMarkdown(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data, null, 2);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [];\n\n lines.push('| ' + cols.join(' | ') + ' |');\n lines.push('| ' + cols.map(() => '---').join(' | ') + ' |');\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n return String(val).replace(/\\|/g, '\\\\|');\n });\n lines.push('| ' + vals.join(' | ') + ' |');\n }\n\n return lines.join('\\n');\n}\n","export function renderCsv(data: unknown, columns?: string[]): string {\n if (!Array.isArray(data) || data.length === 0) {\n return typeof data === 'string' ? data : JSON.stringify(data);\n }\n\n const cols = columns || Object.keys(data[0]);\n const lines: string[] = [cols.join(',')];\n\n for (const row of data) {\n const vals = cols.map((col) => {\n const val = row[col];\n if (val === null || val === undefined) return '';\n const str = String(val);\n return str.includes(',') || str.includes('\"') || str.includes('\\n')\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n });\n lines.push(vals.join(','));\n }\n\n return lines.join('\\n');\n}\n","import yaml from 'js-yaml';\n\nexport function renderYaml(data: unknown): string {\n return yaml.dump(data, { indent: 2, lineWidth: 120 });\n}\n","import type { OutputFormat } from '../types/router.js';\nimport { renderTable } from './table.js';\nimport { renderJson } from './json.js';\nimport { renderMarkdown } from './markdown.js';\nimport { renderCsv } from './csv.js';\nimport { renderYaml } from './yaml.js';\n\nexport function render(data: unknown, format: OutputFormat, columns?: string[]): string {\n switch (format) {\n case 'table': return renderTable(data, columns);\n case 'json': return renderJson(data);\n case 'markdown': return renderMarkdown(data, columns);\n case 'csv': return renderCsv(data, columns);\n case 'yaml': return renderYaml(data);\n default: return renderJson(data);\n }\n}\n"],"mappings":"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","names":[]}
|