Add Beryl Agent and harness source

This commit is contained in:
2026-09-08 20:10:03 +08:00
parent 06d72d001c
commit 47cfbcd66a
70 changed files with 12558 additions and 0 deletions
@@ -0,0 +1,193 @@
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { Type, type TSchema } from "@sinclair/typebox";
import { defineTool, type ToolDefinition } from "@earendil-works/pi-coding-agent";
import type { ImageContent, TextContent } from "@earendil-works/pi-ai/compat";
type McpToolResult = {
content: Array<
| { type: "text"; text: string }
| { type: "image"; data: string; mimeType: string }
| Record<string, unknown>
>;
isError?: boolean;
structuredContent?: Record<string, unknown>;
};
const endpoint = process.env.SWADS_MCP_URL || "https://ads.mincode.cn/mcp";
const maxRows = Math.max(10, Number(process.env.SWADS_MCP_MAX_ROWS) || 50);
const maxTextChars = Math.max(
10_000,
Number(process.env.SWADS_MCP_MAX_TEXT_CHARS) || 60_000,
);
let clientPromise: Promise<Client> | undefined;
export function boundSwadsArguments(
name: string,
args: Record<string, unknown>,
) {
if (name !== "metrics_semantic_query") return args;
const query = args.query;
if (!query || typeof query !== "object" || Array.isArray(query)) return args;
const requested = Number((query as Record<string, unknown>).limit);
return {
...args,
query: {
...query,
limit: Number.isFinite(requested)
? Math.min(Math.max(1, requested), maxRows)
: maxRows,
},
};
}
export function compactSwadsText(text: string) {
try {
const parsed = JSON.parse(text) as Record<string, unknown>;
let originalRows: number | undefined;
let returnedRows: number | undefined;
for (const key of ["rows", "products", "items", "data"]) {
const value = parsed[key];
if (!Array.isArray(value)) continue;
originalRows = value.length;
parsed[key] = value.slice(0, maxRows);
returnedRows = (parsed[key] as unknown[]).length;
break;
}
if (originalRows !== undefined) {
parsed.response_compaction = {
original_rows: originalRows,
returned_rows: returnedRows,
max_rows: maxRows,
note: "Result was bounded for model context safety. Use aggregate queries or narrower filters for additional detail.",
};
}
const compact = JSON.stringify(parsed);
return compact.length <= maxTextChars
? compact
: `${compact.slice(0, maxTextChars)}\n[SWADS_RESULT_TRUNCATED_AT_${maxTextChars}_CHARS]`;
} catch {
return text.length <= maxTextChars
? text
: `${text.slice(0, maxTextChars)}\n[SWADS_RESULT_TRUNCATED_AT_${maxTextChars}_CHARS]`;
}
}
async function swadsClient() {
const token = process.env.SWADS_MCP_TOKEN?.trim();
if (!token)
throw new Error(
"SWADS_MCP_NOT_CONFIGURED: set SWADS_MCP_TOKEN in the server environment",
);
clientPromise ??= (async () => {
const client = new Client({ name: "agent-studio-mini", version: "0.1.0" });
const transport = new StreamableHTTPClientTransport(new URL(endpoint), {
requestInit: { headers: { Authorization: `Bearer ${token}` } },
});
await client.connect(transport);
return client;
})().catch((error) => {
clientPromise = undefined;
throw error;
});
return clientPromise;
}
function asTool(
name: string,
description: string,
parameters: TSchema,
): ToolDefinition {
return defineTool({
name,
label: `SW Ads · ${name}`,
description,
parameters,
execute: async (_id, args, signal) => {
const client = await swadsClient();
const boundedArgs = boundSwadsArguments(
name,
args as Record<string, unknown>,
);
const result = (await client.callTool(
{ name, arguments: boundedArgs },
undefined,
{ signal },
)) as McpToolResult;
const content: Array<TextContent | ImageContent> = [];
for (const item of result.content) {
if (item.type === "text")
content.push({ type: "text", text: compactSwadsText(String(item.text)) });
else if (item.type === "image")
content.push({
type: "image",
data: String(item.data),
mimeType: String(item.mimeType),
});
else content.push({ type: "text", text: JSON.stringify(item) });
}
if (result.isError)
throw new Error(
content
.filter((item) => item.type === "text")
.map((item) => item.text)
.join("\n") || "SWADS_MCP_TOOL_FAILED",
);
return {
content,
details: {
source: "swads-mcp",
contextBounded: true,
maxRows,
maxTextChars,
},
};
},
});
}
const optionalAccount = {
external_account_id: Type.Optional(Type.Union([Type.String(), Type.Null()])),
tenant_id: Type.Optional(Type.String()),
};
export function createSwadsReadTools(): ToolDefinition[] {
return [
asTool(
"swads_whoami",
"Read the current SW Ads identity, visible accounts, capabilities, timezone, and currency.",
Type.Object({}, { additionalProperties: false }),
),
asTool(
"metrics_catalog",
"Read the supported SW Ads metrics, dimensions, and semantic-query schema before querying data.",
Type.Object({}, { additionalProperties: false }),
),
asTool(
"metrics_semantic_query",
"Run a read-only SW Ads semantic metrics query for the current or specified account.",
Type.Object(
{
...optionalAccount,
query: Type.Object({}, { additionalProperties: true }),
},
{ additionalProperties: false },
),
),
asTool(
"commerce_list_products",
"Read the TikTok Shop product catalog and current product metadata.",
Type.Object(
{
...optionalAccount,
authorized_business_center_id: Type.Optional(
Type.Union([Type.String(), Type.Null()]),
),
external_shop_id: Type.Optional(Type.Union([Type.String(), Type.Null()])),
only_selectable: Type.Optional(Type.Boolean()),
},
{ additionalProperties: false },
),
),
];
}