@rankcli/agent-runtime 0.0.1
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 +242 -0
- package/dist/analyzer-2CSWIQGD.mjs +6 -0
- package/dist/chunk-YNZYHEYM.mjs +774 -0
- package/dist/index.d.mts +4012 -0
- package/dist/index.d.ts +4012 -0
- package/dist/index.js +29672 -0
- package/dist/index.mjs +28602 -0
- package/package.json +53 -0
- package/scripts/build-deno.ts +134 -0
- package/src/audit/ai/analyzer.ts +347 -0
- package/src/audit/ai/index.ts +29 -0
- package/src/audit/ai/prompts/content-analysis.ts +271 -0
- package/src/audit/ai/types.ts +179 -0
- package/src/audit/checks/additional-checks.ts +439 -0
- package/src/audit/checks/ai-citation-worthiness.ts +399 -0
- package/src/audit/checks/ai-content-structure.ts +325 -0
- package/src/audit/checks/ai-readiness.ts +339 -0
- package/src/audit/checks/anchor-text.ts +179 -0
- package/src/audit/checks/answer-conciseness.ts +322 -0
- package/src/audit/checks/asset-minification.ts +270 -0
- package/src/audit/checks/bing-optimization.ts +206 -0
- package/src/audit/checks/brand-mention-optimization.ts +349 -0
- package/src/audit/checks/caching-headers.ts +305 -0
- package/src/audit/checks/canonical-advanced.ts +150 -0
- package/src/audit/checks/canonical-domain.ts +196 -0
- package/src/audit/checks/citation-quality.ts +358 -0
- package/src/audit/checks/client-rendering.ts +542 -0
- package/src/audit/checks/color-contrast.ts +342 -0
- package/src/audit/checks/content-freshness.ts +170 -0
- package/src/audit/checks/content-science.ts +589 -0
- package/src/audit/checks/conversion-elements.ts +526 -0
- package/src/audit/checks/crawlability.ts +220 -0
- package/src/audit/checks/directory-listing.ts +172 -0
- package/src/audit/checks/dom-analysis.ts +191 -0
- package/src/audit/checks/dom-size.ts +246 -0
- package/src/audit/checks/duplicate-content.ts +194 -0
- package/src/audit/checks/eeat-signals.ts +990 -0
- package/src/audit/checks/entity-seo.ts +396 -0
- package/src/audit/checks/featured-snippet.ts +473 -0
- package/src/audit/checks/freshness-signals.ts +443 -0
- package/src/audit/checks/funnel-intent.ts +463 -0
- package/src/audit/checks/hreflang.ts +174 -0
- package/src/audit/checks/html-compliance.ts +302 -0
- package/src/audit/checks/image-dimensions.ts +167 -0
- package/src/audit/checks/images.ts +160 -0
- package/src/audit/checks/indexnow.ts +275 -0
- package/src/audit/checks/interactive-tools.ts +475 -0
- package/src/audit/checks/internal-link-graph.ts +436 -0
- package/src/audit/checks/keyword-analysis.ts +239 -0
- package/src/audit/checks/keyword-cannibalization.ts +385 -0
- package/src/audit/checks/keyword-placement.ts +471 -0
- package/src/audit/checks/links.ts +203 -0
- package/src/audit/checks/llms-txt.ts +224 -0
- package/src/audit/checks/local-seo.ts +296 -0
- package/src/audit/checks/mobile.ts +167 -0
- package/src/audit/checks/modern-images.ts +226 -0
- package/src/audit/checks/navboost-signals.ts +395 -0
- package/src/audit/checks/on-page.ts +209 -0
- package/src/audit/checks/page-resources.ts +285 -0
- package/src/audit/checks/pagination.ts +180 -0
- package/src/audit/checks/performance.ts +153 -0
- package/src/audit/checks/platform-presence.ts +580 -0
- package/src/audit/checks/redirect-analysis.ts +153 -0
- package/src/audit/checks/redirect-chain.ts +389 -0
- package/src/audit/checks/resource-hints.ts +420 -0
- package/src/audit/checks/responsive-css.ts +247 -0
- package/src/audit/checks/responsive-images.ts +396 -0
- package/src/audit/checks/review-ecosystem.ts +415 -0
- package/src/audit/checks/robots-validation.ts +373 -0
- package/src/audit/checks/security-headers.ts +172 -0
- package/src/audit/checks/security.ts +144 -0
- package/src/audit/checks/serp-preview.ts +251 -0
- package/src/audit/checks/site-maturity.ts +444 -0
- package/src/audit/checks/social-meta.test.ts +275 -0
- package/src/audit/checks/social-meta.ts +134 -0
- package/src/audit/checks/soft-404.ts +151 -0
- package/src/audit/checks/structured-data.ts +238 -0
- package/src/audit/checks/tech-detection.ts +496 -0
- package/src/audit/checks/topical-clusters.ts +435 -0
- package/src/audit/checks/tracker-bloat.ts +462 -0
- package/src/audit/checks/tracking-verification.test.ts +371 -0
- package/src/audit/checks/tracking-verification.ts +636 -0
- package/src/audit/checks/url-safety.ts +682 -0
- package/src/audit/deno-entry.ts +66 -0
- package/src/audit/discovery/index.ts +15 -0
- package/src/audit/discovery/link-crawler.ts +232 -0
- package/src/audit/discovery/repo-routes.ts +347 -0
- package/src/audit/engine.ts +620 -0
- package/src/audit/fixes/index.ts +209 -0
- package/src/audit/fixes/social-meta-fixes.test.ts +329 -0
- package/src/audit/fixes/social-meta-fixes.ts +463 -0
- package/src/audit/index.ts +74 -0
- package/src/audit/runner.test.ts +299 -0
- package/src/audit/runner.ts +130 -0
- package/src/audit/types.ts +1953 -0
- package/src/content/featured-snippet.ts +367 -0
- package/src/content/generator.test.ts +534 -0
- package/src/content/generator.ts +501 -0
- package/src/content/headline.ts +317 -0
- package/src/content/index.ts +62 -0
- package/src/content/intent.ts +258 -0
- package/src/content/keyword-density.ts +349 -0
- package/src/content/readability.ts +262 -0
- package/src/executor.ts +336 -0
- package/src/fixer.ts +416 -0
- package/src/frameworks/detector.test.ts +248 -0
- package/src/frameworks/detector.ts +371 -0
- package/src/frameworks/index.ts +68 -0
- package/src/frameworks/recipes/angular.yaml +171 -0
- package/src/frameworks/recipes/astro.yaml +206 -0
- package/src/frameworks/recipes/django.yaml +180 -0
- package/src/frameworks/recipes/laravel.yaml +137 -0
- package/src/frameworks/recipes/nextjs.yaml +268 -0
- package/src/frameworks/recipes/nuxt.yaml +175 -0
- package/src/frameworks/recipes/rails.yaml +188 -0
- package/src/frameworks/recipes/react.yaml +202 -0
- package/src/frameworks/recipes/sveltekit.yaml +154 -0
- package/src/frameworks/recipes/vue.yaml +137 -0
- package/src/frameworks/recipes/wordpress.yaml +209 -0
- package/src/frameworks/suggestion-engine.ts +320 -0
- package/src/geo/geo-content.test.ts +305 -0
- package/src/geo/geo-content.ts +266 -0
- package/src/geo/geo-history.test.ts +473 -0
- package/src/geo/geo-history.ts +433 -0
- package/src/geo/geo-tracker.test.ts +359 -0
- package/src/geo/geo-tracker.ts +411 -0
- package/src/geo/index.ts +10 -0
- package/src/git/commit-helper.test.ts +261 -0
- package/src/git/commit-helper.ts +329 -0
- package/src/git/index.ts +12 -0
- package/src/git/pr-helper.test.ts +284 -0
- package/src/git/pr-helper.ts +307 -0
- package/src/index.ts +66 -0
- package/src/keywords/ai-keyword-engine.ts +1062 -0
- package/src/keywords/ai-summarizer.ts +387 -0
- package/src/keywords/ci-mode.ts +555 -0
- package/src/keywords/engine.ts +359 -0
- package/src/keywords/index.ts +151 -0
- package/src/keywords/llm-judge.ts +357 -0
- package/src/keywords/nlp-analysis.ts +706 -0
- package/src/keywords/prioritizer.ts +295 -0
- package/src/keywords/site-crawler.ts +342 -0
- package/src/keywords/sources/autocomplete.ts +139 -0
- package/src/keywords/sources/competitive-search.ts +450 -0
- package/src/keywords/sources/competitor-analysis.ts +374 -0
- package/src/keywords/sources/dataforseo.ts +206 -0
- package/src/keywords/sources/free-sources.ts +294 -0
- package/src/keywords/sources/gsc.ts +123 -0
- package/src/keywords/topic-grouping.ts +327 -0
- package/src/keywords/types.ts +144 -0
- package/src/keywords/wizard.ts +457 -0
- package/src/loader.ts +40 -0
- package/src/reports/index.ts +7 -0
- package/src/reports/report-generator.test.ts +293 -0
- package/src/reports/report-generator.ts +713 -0
- package/src/scheduler/alerts.test.ts +458 -0
- package/src/scheduler/alerts.ts +328 -0
- package/src/scheduler/index.ts +8 -0
- package/src/scheduler/scheduled-audit.test.ts +377 -0
- package/src/scheduler/scheduled-audit.ts +149 -0
- package/src/test/integration-test.ts +325 -0
- package/src/tools/analyzer.ts +373 -0
- package/src/tools/crawl.ts +293 -0
- package/src/tools/files.ts +301 -0
- package/src/tools/h1-fixer.ts +249 -0
- package/src/tools/index.ts +67 -0
- package/src/tracking/github-action.ts +326 -0
- package/src/tracking/google-analytics.ts +265 -0
- package/src/tracking/index.ts +45 -0
- package/src/tracking/report-generator.ts +386 -0
- package/src/tracking/search-console.ts +335 -0
- package/src/types.ts +134 -0
- package/src/utils/http.ts +302 -0
- package/src/wasm-adapter.ts +297 -0
- package/src/wasm-entry.ts +14 -0
- package/tsconfig.json +17 -0
- package/tsup.wasm.config.ts +26 -0
- package/vitest.config.ts +15 -0
package/src/executor.ts
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import type { AgentDefinition, ToolResult, SEOAnalysisResult } from './types.js';
|
|
3
|
+
import { tools } from './tools/index.js';
|
|
4
|
+
import { interpolatePrompt } from './loader.js';
|
|
5
|
+
|
|
6
|
+
export interface ExecuteOptions {
|
|
7
|
+
variables?: Record<string, string>;
|
|
8
|
+
onToolCall?: (name: string, params: Record<string, unknown>) => void;
|
|
9
|
+
onToolResult?: (name: string, result: ToolResult) => void;
|
|
10
|
+
cwd?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ExecutionResult {
|
|
14
|
+
success: boolean;
|
|
15
|
+
data?: unknown;
|
|
16
|
+
error?: string;
|
|
17
|
+
toolCalls?: { name: string; params: unknown; result: ToolResult }[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Map agent tool definitions to Anthropic API tool format
|
|
21
|
+
function mapToolsToAnthropic(agentTools: AgentDefinition['tools']): Anthropic.Tool[] {
|
|
22
|
+
const toolSchemas: Record<string, Anthropic.Tool> = {
|
|
23
|
+
crawl_url: {
|
|
24
|
+
name: 'crawl_url',
|
|
25
|
+
description: 'Fetch and parse HTML from a URL',
|
|
26
|
+
input_schema: {
|
|
27
|
+
type: 'object' as const,
|
|
28
|
+
properties: {
|
|
29
|
+
url: { type: 'string', description: 'URL to crawl' }
|
|
30
|
+
},
|
|
31
|
+
required: ['url']
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
extract_meta: {
|
|
35
|
+
name: 'extract_meta',
|
|
36
|
+
description: 'Extract all meta tags from HTML',
|
|
37
|
+
input_schema: {
|
|
38
|
+
type: 'object' as const,
|
|
39
|
+
properties: {
|
|
40
|
+
html: { type: 'string', description: 'HTML content' },
|
|
41
|
+
url: { type: 'string', description: 'Base URL' }
|
|
42
|
+
},
|
|
43
|
+
required: ['html', 'url']
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
analyze_headings: {
|
|
47
|
+
name: 'analyze_headings',
|
|
48
|
+
description: 'Extract and analyze heading hierarchy',
|
|
49
|
+
input_schema: {
|
|
50
|
+
type: 'object' as const,
|
|
51
|
+
properties: {
|
|
52
|
+
html: { type: 'string', description: 'HTML content' }
|
|
53
|
+
},
|
|
54
|
+
required: ['html']
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
extract_images: {
|
|
58
|
+
name: 'extract_images',
|
|
59
|
+
description: 'Extract all images with their attributes',
|
|
60
|
+
input_schema: {
|
|
61
|
+
type: 'object' as const,
|
|
62
|
+
properties: {
|
|
63
|
+
html: { type: 'string', description: 'HTML content' }
|
|
64
|
+
},
|
|
65
|
+
required: ['html']
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
extract_links: {
|
|
69
|
+
name: 'extract_links',
|
|
70
|
+
description: 'Extract all links from the page',
|
|
71
|
+
input_schema: {
|
|
72
|
+
type: 'object' as const,
|
|
73
|
+
properties: {
|
|
74
|
+
html: { type: 'string', description: 'HTML content' },
|
|
75
|
+
baseUrl: { type: 'string', description: 'Base URL for determining internal/external' }
|
|
76
|
+
},
|
|
77
|
+
required: ['html', 'baseUrl']
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
extract_schema: {
|
|
81
|
+
name: 'extract_schema',
|
|
82
|
+
description: 'Extract JSON-LD structured data',
|
|
83
|
+
input_schema: {
|
|
84
|
+
type: 'object' as const,
|
|
85
|
+
properties: {
|
|
86
|
+
html: { type: 'string', description: 'HTML content' }
|
|
87
|
+
},
|
|
88
|
+
required: ['html']
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
check_robots: {
|
|
92
|
+
name: 'check_robots',
|
|
93
|
+
description: 'Fetch and parse robots.txt',
|
|
94
|
+
input_schema: {
|
|
95
|
+
type: 'object' as const,
|
|
96
|
+
properties: {
|
|
97
|
+
url: { type: 'string', description: 'Base URL of the site' }
|
|
98
|
+
},
|
|
99
|
+
required: ['url']
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
check_sitemap: {
|
|
103
|
+
name: 'check_sitemap',
|
|
104
|
+
description: 'Fetch and parse sitemap.xml',
|
|
105
|
+
input_schema: {
|
|
106
|
+
type: 'object' as const,
|
|
107
|
+
properties: {
|
|
108
|
+
url: { type: 'string', description: 'Base URL of the site' }
|
|
109
|
+
},
|
|
110
|
+
required: ['url']
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
read_file: {
|
|
114
|
+
name: 'read_file',
|
|
115
|
+
description: 'Read a file from the codebase',
|
|
116
|
+
input_schema: {
|
|
117
|
+
type: 'object' as const,
|
|
118
|
+
properties: {
|
|
119
|
+
path: { type: 'string', description: 'File path to read' },
|
|
120
|
+
cwd: { type: 'string', description: 'Working directory' }
|
|
121
|
+
},
|
|
122
|
+
required: ['path']
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
write_file: {
|
|
126
|
+
name: 'write_file',
|
|
127
|
+
description: 'Write content to a file',
|
|
128
|
+
input_schema: {
|
|
129
|
+
type: 'object' as const,
|
|
130
|
+
properties: {
|
|
131
|
+
path: { type: 'string', description: 'File path to write' },
|
|
132
|
+
content: { type: 'string', description: 'Content to write' },
|
|
133
|
+
cwd: { type: 'string', description: 'Working directory' }
|
|
134
|
+
},
|
|
135
|
+
required: ['path', 'content']
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
list_files: {
|
|
139
|
+
name: 'list_files',
|
|
140
|
+
description: 'List files in a directory',
|
|
141
|
+
input_schema: {
|
|
142
|
+
type: 'object' as const,
|
|
143
|
+
properties: {
|
|
144
|
+
path: { type: 'string', description: 'Directory path' },
|
|
145
|
+
pattern: { type: 'string', description: 'File pattern to match' },
|
|
146
|
+
recursive: { type: 'boolean', description: 'Search recursively' },
|
|
147
|
+
cwd: { type: 'string', description: 'Working directory' }
|
|
148
|
+
},
|
|
149
|
+
required: ['path']
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
detect_framework: {
|
|
153
|
+
name: 'detect_framework',
|
|
154
|
+
description: 'Detect the web framework used in a project',
|
|
155
|
+
input_schema: {
|
|
156
|
+
type: 'object' as const,
|
|
157
|
+
properties: {
|
|
158
|
+
cwd: { type: 'string', description: 'Project directory' }
|
|
159
|
+
},
|
|
160
|
+
required: []
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
find_html_entry: {
|
|
164
|
+
name: 'find_html_entry',
|
|
165
|
+
description: 'Find the HTML entry point file',
|
|
166
|
+
input_schema: {
|
|
167
|
+
type: 'object' as const,
|
|
168
|
+
properties: {
|
|
169
|
+
cwd: { type: 'string', description: 'Project directory' }
|
|
170
|
+
},
|
|
171
|
+
required: []
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
find_page_files: {
|
|
175
|
+
name: 'find_page_files',
|
|
176
|
+
description: 'Find all page/route files in the project',
|
|
177
|
+
input_schema: {
|
|
178
|
+
type: 'object' as const,
|
|
179
|
+
properties: {
|
|
180
|
+
cwd: { type: 'string', description: 'Project directory' },
|
|
181
|
+
framework: { type: 'string', description: 'Framework name' }
|
|
182
|
+
},
|
|
183
|
+
required: []
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
analyze_url: {
|
|
187
|
+
name: 'analyze_url',
|
|
188
|
+
description: 'Run a complete SEO analysis on a URL',
|
|
189
|
+
input_schema: {
|
|
190
|
+
type: 'object' as const,
|
|
191
|
+
properties: {
|
|
192
|
+
url: { type: 'string', description: 'URL to analyze' }
|
|
193
|
+
},
|
|
194
|
+
required: ['url']
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
return agentTools
|
|
200
|
+
.filter(t => toolSchemas[t.name])
|
|
201
|
+
.map(t => toolSchemas[t.name]);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export async function executeAgent(
|
|
205
|
+
agent: AgentDefinition,
|
|
206
|
+
options: ExecuteOptions = {}
|
|
207
|
+
): Promise<ExecutionResult> {
|
|
208
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
209
|
+
if (!apiKey) {
|
|
210
|
+
return { success: false, error: 'ANTHROPIC_API_KEY environment variable not set' };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const client = new Anthropic({ apiKey });
|
|
214
|
+
const { variables = {}, onToolCall, onToolResult, cwd } = options;
|
|
215
|
+
|
|
216
|
+
// Interpolate the prompt with variables
|
|
217
|
+
const userPrompt = interpolatePrompt(agent.prompt, variables);
|
|
218
|
+
|
|
219
|
+
// Map agent tools to Anthropic format
|
|
220
|
+
const anthropicTools = mapToolsToAnthropic(agent.tools);
|
|
221
|
+
|
|
222
|
+
const toolCalls: { name: string; params: unknown; result: ToolResult }[] = [];
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
// Initial message
|
|
226
|
+
const messages: Anthropic.MessageParam[] = [
|
|
227
|
+
{ role: 'user', content: userPrompt }
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
let response = await client.messages.create({
|
|
231
|
+
model: agent.model,
|
|
232
|
+
max_tokens: agent.max_tokens,
|
|
233
|
+
temperature: agent.temperature,
|
|
234
|
+
system: agent.system,
|
|
235
|
+
tools: anthropicTools.length > 0 ? anthropicTools : undefined,
|
|
236
|
+
messages,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
// Process tool calls in a loop
|
|
240
|
+
while (response.stop_reason === 'tool_use') {
|
|
241
|
+
const toolUseBlocks = response.content.filter(
|
|
242
|
+
(block): block is Anthropic.ToolUseBlock => block.type === 'tool_use'
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
const toolResults: Anthropic.ToolResultBlockParam[] = [];
|
|
246
|
+
|
|
247
|
+
for (const toolUse of toolUseBlocks) {
|
|
248
|
+
const toolName = toolUse.name;
|
|
249
|
+
const toolParams = toolUse.input as Record<string, unknown>;
|
|
250
|
+
|
|
251
|
+
// Add cwd to file-related tools
|
|
252
|
+
if (['read_file', 'write_file', 'list_files', 'detect_framework', 'find_html_entry', 'find_page_files'].includes(toolName)) {
|
|
253
|
+
if (cwd && !toolParams.cwd) {
|
|
254
|
+
toolParams.cwd = cwd;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
onToolCall?.(toolName, toolParams);
|
|
259
|
+
|
|
260
|
+
const toolFn = tools[toolName];
|
|
261
|
+
let result: ToolResult;
|
|
262
|
+
|
|
263
|
+
if (toolFn) {
|
|
264
|
+
result = await toolFn(toolParams);
|
|
265
|
+
} else {
|
|
266
|
+
result = { success: false, error: `Unknown tool: ${toolName}` };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
onToolResult?.(toolName, result);
|
|
270
|
+
toolCalls.push({ name: toolName, params: toolParams, result });
|
|
271
|
+
|
|
272
|
+
toolResults.push({
|
|
273
|
+
type: 'tool_result',
|
|
274
|
+
tool_use_id: toolUse.id,
|
|
275
|
+
content: JSON.stringify(result),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Continue conversation with tool results
|
|
280
|
+
messages.push({ role: 'assistant', content: response.content });
|
|
281
|
+
messages.push({ role: 'user', content: toolResults });
|
|
282
|
+
|
|
283
|
+
response = await client.messages.create({
|
|
284
|
+
model: agent.model,
|
|
285
|
+
max_tokens: agent.max_tokens,
|
|
286
|
+
temperature: agent.temperature,
|
|
287
|
+
system: agent.system,
|
|
288
|
+
tools: anthropicTools,
|
|
289
|
+
messages,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// Extract final text response
|
|
294
|
+
const textBlocks = response.content.filter(
|
|
295
|
+
(block): block is Anthropic.TextBlock => block.type === 'text'
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const responseText = textBlocks.map(b => b.text).join('\n');
|
|
299
|
+
|
|
300
|
+
// Try to parse JSON from the response
|
|
301
|
+
let data: unknown;
|
|
302
|
+
try {
|
|
303
|
+
// Look for JSON in the response
|
|
304
|
+
const jsonMatch = responseText.match(/```json\n?([\s\S]*?)\n?```/) ||
|
|
305
|
+
responseText.match(/\{[\s\S]*\}/);
|
|
306
|
+
if (jsonMatch) {
|
|
307
|
+
const jsonStr = jsonMatch[1] || jsonMatch[0];
|
|
308
|
+
data = JSON.parse(jsonStr);
|
|
309
|
+
} else {
|
|
310
|
+
data = responseText;
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
data = responseText;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return { success: true, data, toolCalls };
|
|
317
|
+
} catch (error) {
|
|
318
|
+
return {
|
|
319
|
+
success: false,
|
|
320
|
+
error: error instanceof Error ? error.message : 'Agent execution failed',
|
|
321
|
+
toolCalls,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Simplified direct analysis function that doesn't need Claude API
|
|
327
|
+
export async function runDirectAnalysis(url: string): Promise<SEOAnalysisResult> {
|
|
328
|
+
const { analyzeUrl } = await import('./tools/analyzer.js');
|
|
329
|
+
const result = await analyzeUrl({ url });
|
|
330
|
+
|
|
331
|
+
if (!result.success || !result.data) {
|
|
332
|
+
throw new Error(result.error || 'Analysis failed');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
return result.data as SEOAnalysisResult;
|
|
336
|
+
}
|