@crawlcheck/sdk 1.9.1 → 1.10.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 CHANGED
@@ -35,16 +35,19 @@ Since 1.8.0 they also apply the signing policy (https://crawlcheck.io/keys#polic
35
35
  Three tools your agent can call itself: `crawlcheck_check_site` (the signed, verified decision for an action on a site, including the business facts the site publishes and which AI engines get them wrong), `crawlcheck_verify_fact` (one signed verdict on a phone number, address, hours or service area you hold: does the business publish it, did it once, or whose is it) and `crawlcheck_fetch` (fetches a page only after its domain, and every redirect hop, is allowed). All fail closed.
36
36
 
37
37
  ```js
38
- import { CrawlCheck, agentTools, toolsFor } from "@crawlcheck/sdk";
38
+ import { CrawlCheck, agentTools, toolsFor, vercelTools, langchainTools } from "@crawlcheck/sdk";
39
39
  const tools = agentTools(new CrawlCheck(), { agent: "MyAgentBot" });
40
40
 
41
41
  // OpenAI function calling
42
42
  const oa = toolsFor("openai", tools); // oa.tools → tools: [...]; on a tool call: await oa.call(name, argumentsJson)
43
43
  // Anthropic tool use
44
44
  const an = toolsFor("anthropic", tools); // an.tools → tools: [...]; on tool_use: await an.call(block.name, block.input)
45
- // Vercel AI SDK
46
- import { tool, jsonSchema } from "ai";
47
- const vt = Object.fromEntries(tools.map((t) => [t.name, tool({ description: t.description, parameters: jsonSchema(t.parameters), execute: t.execute })]));
45
+ // Vercel AI SDK (1.10.0): one call; the "ai" module is passed in, so this package keeps no dependency
46
+ import * as ai from "ai";
47
+ const vt = vercelTools(new CrawlCheck(), ai); // generateText({ model, tools: vt, ... })
48
+ // LangChain.js (1.10.0)
49
+ import * as lc from "@langchain/core/tools";
50
+ const lt = langchainTools(new CrawlCheck(), lc); // createAgent({ model, tools: lt }) or model.bindTools(lt)
48
51
  // An MCP server you run
49
52
  const mc = toolsFor("mcp", tools); // list mc.tools; answer tools/call with mc.call(name, args)
50
53
  ```
@@ -1895,7 +1895,7 @@ export interface paths {
1895
1895
  path?: never;
1896
1896
  cookie?: never;
1897
1897
  };
1898
- /** The last reconstruction test: the oldest archived records' evidence paths (record, report node, decision nodes, manifest node, every verifier check) resolved through the 90-day projections and again from the permanent store alone (R2 archive + seal records), compared byte for byte after canonical serialisation. Public */
1898
+ /** The last reconstruction test: the oldest archived records' evidence paths (record, report node, decision nodes, manifest node, every verifier check) resolved through the 90-day projections and again from the permanent store alone (the sealed archive and seal records), compared byte for byte after canonical serialisation. Public */
1899
1899
  get: operations["reconstructionTest"];
1900
1900
  put?: never;
1901
1901
  post?: never;
package/dist/index.d.ts CHANGED
@@ -762,4 +762,23 @@ export declare function toolsFor(format: ToolFormat, tools: AgentTool[]): {
762
762
  tools: unknown;
763
763
  call: (name: string, args: unknown) => Promise<JsonObject>;
764
764
  };
765
+ /** Structural view of the Vercel AI SDK module ("ai") - passed in, so this package keeps no dependency. */
766
+ export interface VercelAiModule {
767
+ tool: (def: any) => any;
768
+ jsonSchema: (schema: any) => any;
769
+ }
770
+ /** Vercel AI SDK adapter (1.10.0): `import * as ai from "ai"; const tools = vercelTools(cc, ai);` then generateText({ tools, ... }).
771
+ * Same three tools as agentTools(); they fail closed. The schema is given as both inputSchema (AI SDK 5+) and parameters (AI SDK 4). */
772
+ export declare function vercelTools(cc: CrawlCheck, ai: VercelAiModule, opts?: AgentToolOptions): Record<string, unknown>;
773
+ /** Structural view of "@langchain/core/tools" - passed in, so this package keeps no dependency. */
774
+ export interface LangChainToolsModule {
775
+ tool: (fn: (input: any) => any, fields: {
776
+ name: string;
777
+ description: string;
778
+ schema: any;
779
+ }) => any;
780
+ }
781
+ /** LangChain.js adapter (1.10.0): `import * as lc from "@langchain/core/tools"; const tools = langchainTools(cc, lc);`
782
+ * Same three tools as agentTools(); each returns its result as a JSON string; they fail closed. */
783
+ export declare function langchainTools(cc: CrawlCheck, lc: LangChainToolsModule, opts?: AgentToolOptions): unknown[];
765
784
  export default CrawlCheck;
package/dist/index.js CHANGED
@@ -608,7 +608,11 @@ function atDomain(v) { const s = String(v ?? "").trim(); try {
608
608
  catch {
609
609
  return "";
610
610
  } }
611
- function atAction(v) { return AT_ACTIONS.includes(String(v)) ? String(v) : "read"; }
611
+ // 1.9.2: an action that is GIVEN but not one of the five fails closed (it used to fall back to "read", so a crew asking about
612
+ // "pay" got a read decision). An absent action still means read.
613
+ function atAction(v) { if (v === undefined || v === null || v === "")
614
+ return "read"; return AT_ACTIONS.includes(String(v)) ? String(v) : null; }
615
+ const atBadAction = (v) => ({ proceed: false, why: ["unknown action: " + String(v) + " (use read, cite, connect, transact or administer)"] });
612
616
  export function agentTools(cc, opts = {}) {
613
617
  const max = opts.maxChars ?? 20000;
614
618
  return [
@@ -620,6 +624,8 @@ export function agentTools(cc, opts = {}) {
620
624
  } },
621
625
  execute: async (a) => {
622
626
  const domain = atDomain(a?.site), action = atAction(a?.action);
627
+ if (!action)
628
+ return atBadAction(a?.action);
623
629
  if (!domain)
624
630
  return { proceed: false, why: ["not a public domain name: " + String(a?.site ?? "")] };
625
631
  const g = await cc.guard(domain, action, opts);
@@ -657,6 +663,8 @@ export function agentTools(cc, opts = {}) {
657
663
  action: { type: "string", enum: ["read", "cite"], description: "read (default) or cite, if the text will be quoted back to someone" }
658
664
  } },
659
665
  execute: async (a) => {
666
+ if (a?.action !== undefined && a?.action !== null && a?.action !== "" && a.action !== "read" && a.action !== "cite")
667
+ return Object.assign(atBadAction(a.action), { url: String(a?.url ?? "") });
660
668
  const r = await cc.guardedFetch(String(a?.url ?? ""), Object.assign({}, opts, { action: (a?.action === "cite" ? "cite" : "read") }));
661
669
  const hops = r.hops.map((h) => ({ url: h.url, domain: h.domain, decision: h.decision, proceed: h.proceed, status: h.status ?? null }));
662
670
  if (!r.proceed || !r.response)
@@ -684,4 +692,18 @@ export function toolsFor(format, tools) {
684
692
  return { tools: tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.parameters, annotations: { readOnlyHint: true, openWorldHint: true } })), call };
685
693
  return { tools: Object.fromEntries(tools.map((t) => [t.name, { description: t.description, parameters: t.parameters, execute: t.execute }])), call };
686
694
  }
695
+ /** Vercel AI SDK adapter (1.10.0): `import * as ai from "ai"; const tools = vercelTools(cc, ai);` then generateText({ tools, ... }).
696
+ * Same three tools as agentTools(); they fail closed. The schema is given as both inputSchema (AI SDK 5+) and parameters (AI SDK 4). */
697
+ export function vercelTools(cc, ai, opts = {}) {
698
+ if (!ai || typeof ai.tool !== "function" || typeof ai.jsonSchema !== "function")
699
+ throw new Error('vercelTools needs the "ai" module: import * as ai from "ai"');
700
+ return Object.fromEntries(agentTools(cc, opts).map((t) => { const sc = ai.jsonSchema(t.parameters); return [t.name, ai.tool({ description: t.description, inputSchema: sc, parameters: sc, execute: (args) => t.execute(args) })]; }));
701
+ }
702
+ /** LangChain.js adapter (1.10.0): `import * as lc from "@langchain/core/tools"; const tools = langchainTools(cc, lc);`
703
+ * Same three tools as agentTools(); each returns its result as a JSON string; they fail closed. */
704
+ export function langchainTools(cc, lc, opts = {}) {
705
+ if (!lc || typeof lc.tool !== "function")
706
+ throw new Error('langchainTools needs "@langchain/core/tools": import * as lc from "@langchain/core/tools"');
707
+ return agentTools(cc, opts).map((t) => lc.tool(async (input) => JSON.stringify(await t.execute(input ?? {})), { name: t.name, description: t.description, schema: t.parameters }));
708
+ }
687
709
  export default CrawlCheck;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlcheck/sdk",
3
- "version": "1.9.1",
3
+ "version": "1.10.0",
4
4
  "description": "Typed client for the CrawlCheck API (generated from its OpenAPI document) and the zero-dependency offline verifier for evidence bundles and remediation receipts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -44,3 +44,10 @@ test("live: verify_fact returns a signed verdict that verifies", async () => {
44
44
  if (r.ok) { assert.equal(r.kind, "crawlcheck-field-check"); assert.equal(r.verified, true); assert.ok(r.verdict); }
45
45
  else assert.ok(r.why.length);
46
46
  });
47
+
48
+ test("1.9.2: an unknown action fails closed (no fallback to read), without calling the API", async () => {
49
+ const r = await tools[0].execute({ site: "crawlcheck.io", action: "pay" });
50
+ assert.equal(r.proceed, false); assert.match(r.why[0], /unknown action: pay/);
51
+ const f = await tools[2].execute({ url: "https://crawlcheck.io/", action: "transact" });
52
+ assert.equal(f.proceed, false); assert.match(f.why[0], /unknown action/);
53
+ });