mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-17 09:02:12 +00:00
add agent schemas
This commit is contained in:
commit
c4153c5335
20 changed files with 2735 additions and 0 deletions
271
resources/agent-schemas/src/amp.ts
Normal file
271
resources/agent-schemas/src/amp.ts
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
import * as cheerio from "cheerio";
|
||||
import { fetchWithCache } from "./cache.js";
|
||||
import { createNormalizedSchema, type NormalizedSchema } from "./normalize.js";
|
||||
import type { JSONSchema7 } from "json-schema";
|
||||
|
||||
const AMP_DOCS_URL = "https://ampcode.com/manual/appendix";
|
||||
|
||||
// Key types we want to extract
|
||||
const TARGET_TYPES = ["StreamJSONMessage", "AmpOptions", "PermissionRule", "Message", "ToolCall"];
|
||||
|
||||
export async function extractAmpSchema(): Promise<NormalizedSchema> {
|
||||
console.log("Extracting AMP schema from documentation...");
|
||||
|
||||
try {
|
||||
const html = await fetchWithCache(AMP_DOCS_URL);
|
||||
const $ = cheerio.load(html);
|
||||
|
||||
// Find TypeScript code blocks
|
||||
const codeBlocks: string[] = [];
|
||||
$("pre code").each((_, el) => {
|
||||
const code = $(el).text();
|
||||
// Look for TypeScript interface/type definitions
|
||||
if (
|
||||
code.includes("interface ") ||
|
||||
code.includes("type ") ||
|
||||
code.includes(": {") ||
|
||||
code.includes("export ")
|
||||
) {
|
||||
codeBlocks.push(code);
|
||||
}
|
||||
});
|
||||
|
||||
if (codeBlocks.length === 0) {
|
||||
console.log(" [warn] No TypeScript code blocks found, using fallback schema");
|
||||
return createFallbackSchema();
|
||||
}
|
||||
|
||||
console.log(` [found] ${codeBlocks.length} code blocks`);
|
||||
|
||||
// Parse TypeScript definitions into schemas
|
||||
const definitions = parseTypeScriptToSchema(codeBlocks.join("\n"));
|
||||
|
||||
// Verify target types exist
|
||||
const found = TARGET_TYPES.filter((name) => definitions[name]);
|
||||
const missing = TARGET_TYPES.filter((name) => !definitions[name]);
|
||||
|
||||
if (missing.length > 0) {
|
||||
console.log(` [warn] Missing expected types: ${missing.join(", ")}`);
|
||||
}
|
||||
|
||||
if (Object.keys(definitions).length === 0) {
|
||||
console.log(" [warn] No types extracted, using fallback schema");
|
||||
return createFallbackSchema();
|
||||
}
|
||||
|
||||
console.log(` [ok] Extracted ${Object.keys(definitions).length} types (${found.length} target types)`);
|
||||
|
||||
return createNormalizedSchema("amp", "AMP Code SDK Schema", definitions);
|
||||
} catch (error) {
|
||||
console.log(` [error] Failed to fetch docs: ${error}`);
|
||||
console.log(" [fallback] Using embedded schema definitions");
|
||||
return createFallbackSchema();
|
||||
}
|
||||
}
|
||||
|
||||
function parseTypeScriptToSchema(code: string): Record<string, JSONSchema7> {
|
||||
const definitions: Record<string, JSONSchema7> = {};
|
||||
|
||||
// Match interface definitions
|
||||
const interfaceRegex = /(?:export\s+)?interface\s+(\w+)\s*(?:extends\s+[\w,\s]+)?\s*\{([^}]+)\}/g;
|
||||
let match;
|
||||
|
||||
while ((match = interfaceRegex.exec(code)) !== null) {
|
||||
const [, name, body] = match;
|
||||
definitions[name] = parseInterfaceBody(body);
|
||||
}
|
||||
|
||||
// Match type definitions (simple object types)
|
||||
const typeRegex = /(?:export\s+)?type\s+(\w+)\s*=\s*\{([^}]+)\}/g;
|
||||
|
||||
while ((match = typeRegex.exec(code)) !== null) {
|
||||
const [, name, body] = match;
|
||||
definitions[name] = parseInterfaceBody(body);
|
||||
}
|
||||
|
||||
// Match union type definitions
|
||||
const unionRegex = /(?:export\s+)?type\s+(\w+)\s*=\s*([^;{]+);/g;
|
||||
|
||||
while ((match = unionRegex.exec(code)) !== null) {
|
||||
const [, name, body] = match;
|
||||
if (body.includes("|")) {
|
||||
definitions[name] = parseUnionType(body);
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
function parseInterfaceBody(body: string): JSONSchema7 {
|
||||
const properties: Record<string, JSONSchema7> = {};
|
||||
const required: string[] = [];
|
||||
|
||||
// Match property definitions
|
||||
const propRegex = /(\w+)(\?)?:\s*([^;]+);/g;
|
||||
let match;
|
||||
|
||||
while ((match = propRegex.exec(body)) !== null) {
|
||||
const [, propName, optional, propType] = match;
|
||||
properties[propName] = typeToSchema(propType.trim());
|
||||
|
||||
if (!optional) {
|
||||
required.push(propName);
|
||||
}
|
||||
}
|
||||
|
||||
const schema: JSONSchema7 = {
|
||||
type: "object",
|
||||
properties,
|
||||
};
|
||||
|
||||
if (required.length > 0) {
|
||||
schema.required = required;
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
function typeToSchema(tsType: string): JSONSchema7 {
|
||||
// Handle union types
|
||||
if (tsType.includes("|")) {
|
||||
return parseUnionType(tsType);
|
||||
}
|
||||
|
||||
// Handle array types
|
||||
if (tsType.endsWith("[]")) {
|
||||
const itemType = tsType.slice(0, -2);
|
||||
return {
|
||||
type: "array",
|
||||
items: typeToSchema(itemType),
|
||||
};
|
||||
}
|
||||
|
||||
// Handle Array<T>
|
||||
const arrayMatch = tsType.match(/^Array<(.+)>$/);
|
||||
if (arrayMatch) {
|
||||
return {
|
||||
type: "array",
|
||||
items: typeToSchema(arrayMatch[1]),
|
||||
};
|
||||
}
|
||||
|
||||
// Handle basic types
|
||||
switch (tsType) {
|
||||
case "string":
|
||||
return { type: "string" };
|
||||
case "number":
|
||||
return { type: "number" };
|
||||
case "boolean":
|
||||
return { type: "boolean" };
|
||||
case "null":
|
||||
return { type: "null" };
|
||||
case "any":
|
||||
case "unknown":
|
||||
return {};
|
||||
case "object":
|
||||
return { type: "object" };
|
||||
default:
|
||||
// Could be a reference to another type
|
||||
if (/^[A-Z]/.test(tsType)) {
|
||||
return { $ref: `#/definitions/${tsType}` };
|
||||
}
|
||||
// String literal
|
||||
if (tsType.startsWith('"') || tsType.startsWith("'")) {
|
||||
return { type: "string", const: tsType.slice(1, -1) };
|
||||
}
|
||||
return { type: "string" };
|
||||
}
|
||||
}
|
||||
|
||||
function parseUnionType(unionStr: string): JSONSchema7 {
|
||||
const parts = unionStr.split("|").map((p) => p.trim());
|
||||
|
||||
// Check if it's a string literal union
|
||||
const allStringLiterals = parts.every((p) => p.startsWith('"') || p.startsWith("'"));
|
||||
|
||||
if (allStringLiterals) {
|
||||
return {
|
||||
type: "string",
|
||||
enum: parts.map((p) => p.slice(1, -1)),
|
||||
};
|
||||
}
|
||||
|
||||
// General union
|
||||
return {
|
||||
oneOf: parts.map((p) => typeToSchema(p)),
|
||||
};
|
||||
}
|
||||
|
||||
function createFallbackSchema(): NormalizedSchema {
|
||||
// Fallback schema based on AMP documentation structure
|
||||
const definitions: Record<string, JSONSchema7> = {
|
||||
StreamJSONMessage: {
|
||||
type: "object",
|
||||
properties: {
|
||||
type: {
|
||||
type: "string",
|
||||
enum: ["message", "tool_call", "tool_result", "error", "done"],
|
||||
},
|
||||
id: { type: "string" },
|
||||
content: { type: "string" },
|
||||
tool_call: { $ref: "#/definitions/ToolCall" },
|
||||
error: { type: "string" },
|
||||
},
|
||||
required: ["type"],
|
||||
},
|
||||
AmpOptions: {
|
||||
type: "object",
|
||||
properties: {
|
||||
model: { type: "string" },
|
||||
apiKey: { type: "string" },
|
||||
baseURL: { type: "string" },
|
||||
maxTokens: { type: "number" },
|
||||
temperature: { type: "number" },
|
||||
systemPrompt: { type: "string" },
|
||||
tools: { type: "array", items: { type: "object" } },
|
||||
workingDirectory: { type: "string" },
|
||||
permissionRules: {
|
||||
type: "array",
|
||||
items: { $ref: "#/definitions/PermissionRule" },
|
||||
},
|
||||
},
|
||||
},
|
||||
PermissionRule: {
|
||||
type: "object",
|
||||
properties: {
|
||||
tool: { type: "string" },
|
||||
action: { type: "string", enum: ["allow", "deny", "ask"] },
|
||||
pattern: { type: "string" },
|
||||
description: { type: "string" },
|
||||
},
|
||||
required: ["tool", "action"],
|
||||
},
|
||||
Message: {
|
||||
type: "object",
|
||||
properties: {
|
||||
role: { type: "string", enum: ["user", "assistant", "system"] },
|
||||
content: { type: "string" },
|
||||
tool_calls: {
|
||||
type: "array",
|
||||
items: { $ref: "#/definitions/ToolCall" },
|
||||
},
|
||||
},
|
||||
required: ["role", "content"],
|
||||
},
|
||||
ToolCall: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "string" },
|
||||
name: { type: "string" },
|
||||
arguments: {
|
||||
oneOf: [{ type: "string" }, { type: "object" }],
|
||||
},
|
||||
},
|
||||
required: ["id", "name", "arguments"],
|
||||
},
|
||||
};
|
||||
|
||||
console.log(` [ok] Using fallback schema with ${Object.keys(definitions).length} definitions`);
|
||||
|
||||
return createNormalizedSchema("amp", "AMP Code SDK Schema", definitions);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue