@youdotcom-oss/api 0.1.1 → 0.2.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.
Files changed (31) hide show
  1. package/README.md +36 -36
  2. package/bin/cli.js +233 -400
  3. package/package.json +1 -1
  4. package/src/cli.ts +92 -21
  5. package/src/contents/contents.schemas.ts +8 -7
  6. package/src/contents/tests/contents.request.spec.ts +109 -0
  7. package/src/contents/tests/contents.schema-validation.spec.ts +75 -0
  8. package/src/deep-search/deep-search.schemas.ts +48 -0
  9. package/src/deep-search/deep-search.utils.ts +79 -0
  10. package/src/deep-search/tests/deep-search.request.spec.ts +109 -0
  11. package/src/deep-search/tests/deep-search.schema-validation.spec.ts +71 -0
  12. package/src/deep-search/tests/deep-search.utils.docker.ts +139 -0
  13. package/src/main.ts +4 -3
  14. package/src/search/search.schemas.ts +65 -6
  15. package/src/search/search.utils.ts +6 -28
  16. package/src/search/tests/search.request.spec.ts +122 -0
  17. package/src/search/tests/search.schema-validation.spec.ts +152 -0
  18. package/src/search/tests/{search.utils.spec.ts → search.utils.docker.ts} +0 -10
  19. package/src/shared/api.constants.ts +1 -1
  20. package/src/shared/check-response-for-errors.ts +1 -1
  21. package/src/shared/command-runner.ts +95 -0
  22. package/src/shared/dry-run-utils.ts +141 -0
  23. package/src/shared/tests/command-runner.spec.ts +210 -0
  24. package/src/shared/use-get-user-agents.ts +1 -1
  25. package/src/commands/contents.ts +0 -52
  26. package/src/commands/express.ts +0 -52
  27. package/src/commands/search.ts +0 -52
  28. package/src/express/express.schemas.ts +0 -85
  29. package/src/express/express.utils.ts +0 -113
  30. package/src/express/tests/express.utils.spec.ts +0 -83
  31. /package/src/contents/tests/{contents.utils.spec.ts → contents.utils.docker.ts} +0 -0
package/bin/cli.js CHANGED
@@ -11,11 +11,11 @@ var __export = (target, all) => {
11
11
  };
12
12
 
13
13
  // src/cli.ts
14
- import { parseArgs as parseArgs4 } from "node:util";
14
+ import { parseArgs as parseArgs2 } from "node:util";
15
15
  // package.json
16
16
  var package_default = {
17
17
  name: "@youdotcom-oss/api",
18
- version: "0.1.1",
18
+ version: "0.2.1",
19
19
  description: "You.com API client with bundled CLI for agents supporting Agent Skills",
20
20
  license: "MIT",
21
21
  engines: {
@@ -82,9 +82,6 @@ var package_default = {
82
82
  }
83
83
  };
84
84
 
85
- // src/commands/contents.ts
86
- import { parseArgs } from "node:util";
87
-
88
85
  // ../../node_modules/.bun/zod@4.3.6/node_modules/zod/v4/core/core.js
89
86
  var NEVER = Object.freeze({
90
87
  status: "aborted"
@@ -2340,114 +2337,6 @@ function handleIntersectionResults(result, left, right) {
2340
2337
  result.value = merged.data;
2341
2338
  return result;
2342
2339
  }
2343
- var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
2344
- $ZodType.init(inst, def);
2345
- inst._zod.parse = (payload, ctx) => {
2346
- const input = payload.value;
2347
- if (!isPlainObject(input)) {
2348
- payload.issues.push({
2349
- expected: "record",
2350
- code: "invalid_type",
2351
- input,
2352
- inst
2353
- });
2354
- return payload;
2355
- }
2356
- const proms = [];
2357
- const values = def.keyType._zod.values;
2358
- if (values) {
2359
- payload.value = {};
2360
- const recordKeys = new Set;
2361
- for (const key of values) {
2362
- if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
2363
- recordKeys.add(typeof key === "number" ? key.toString() : key);
2364
- const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
2365
- if (result instanceof Promise) {
2366
- proms.push(result.then((result2) => {
2367
- if (result2.issues.length) {
2368
- payload.issues.push(...prefixIssues(key, result2.issues));
2369
- }
2370
- payload.value[key] = result2.value;
2371
- }));
2372
- } else {
2373
- if (result.issues.length) {
2374
- payload.issues.push(...prefixIssues(key, result.issues));
2375
- }
2376
- payload.value[key] = result.value;
2377
- }
2378
- }
2379
- }
2380
- let unrecognized;
2381
- for (const key in input) {
2382
- if (!recordKeys.has(key)) {
2383
- unrecognized = unrecognized ?? [];
2384
- unrecognized.push(key);
2385
- }
2386
- }
2387
- if (unrecognized && unrecognized.length > 0) {
2388
- payload.issues.push({
2389
- code: "unrecognized_keys",
2390
- input,
2391
- inst,
2392
- keys: unrecognized
2393
- });
2394
- }
2395
- } else {
2396
- payload.value = {};
2397
- for (const key of Reflect.ownKeys(input)) {
2398
- if (key === "__proto__")
2399
- continue;
2400
- let keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
2401
- if (keyResult instanceof Promise) {
2402
- throw new Error("Async schemas not supported in object keys currently");
2403
- }
2404
- const checkNumericKey = typeof key === "string" && number.test(key) && keyResult.issues.length;
2405
- if (checkNumericKey) {
2406
- const retryResult = def.keyType._zod.run({ value: Number(key), issues: [] }, ctx);
2407
- if (retryResult instanceof Promise) {
2408
- throw new Error("Async schemas not supported in object keys currently");
2409
- }
2410
- if (retryResult.issues.length === 0) {
2411
- keyResult = retryResult;
2412
- }
2413
- }
2414
- if (keyResult.issues.length) {
2415
- if (def.mode === "loose") {
2416
- payload.value[key] = input[key];
2417
- } else {
2418
- payload.issues.push({
2419
- code: "invalid_key",
2420
- origin: "record",
2421
- issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
2422
- input: key,
2423
- path: [key],
2424
- inst
2425
- });
2426
- }
2427
- continue;
2428
- }
2429
- const result = def.valueType._zod.run({ value: input[key], issues: [] }, ctx);
2430
- if (result instanceof Promise) {
2431
- proms.push(result.then((result2) => {
2432
- if (result2.issues.length) {
2433
- payload.issues.push(...prefixIssues(key, result2.issues));
2434
- }
2435
- payload.value[keyResult.value] = result2.value;
2436
- }));
2437
- } else {
2438
- if (result.issues.length) {
2439
- payload.issues.push(...prefixIssues(key, result.issues));
2440
- }
2441
- payload.value[keyResult.value] = result.value;
2442
- }
2443
- }
2444
- }
2445
- if (proms.length) {
2446
- return Promise.all(proms).then(() => payload);
2447
- }
2448
- return payload;
2449
- };
2450
- });
2451
2340
  var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
2452
2341
  $ZodType.init(inst, def);
2453
2342
  const values = getEnumValues(def.entries);
@@ -2468,28 +2357,6 @@ var $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
2468
2357
  return payload;
2469
2358
  };
2470
2359
  });
2471
- var $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
2472
- $ZodType.init(inst, def);
2473
- if (def.values.length === 0) {
2474
- throw new Error("Cannot create literal schema with no valid values");
2475
- }
2476
- const values = new Set(def.values);
2477
- inst._zod.values = values;
2478
- inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
2479
- inst._zod.parse = (payload, _ctx) => {
2480
- const input = payload.value;
2481
- if (values.has(input)) {
2482
- return payload;
2483
- }
2484
- payload.issues.push({
2485
- code: "invalid_value",
2486
- values: def.values,
2487
- input,
2488
- inst
2489
- });
2490
- return payload;
2491
- };
2492
- });
2493
2360
  var $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def) => {
2494
2361
  $ZodType.init(inst, def);
2495
2362
  inst._zod.parse = (payload, ctx) => {
@@ -4663,21 +4530,6 @@ function intersection(left, right) {
4663
4530
  right
4664
4531
  });
4665
4532
  }
4666
- var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
4667
- $ZodRecord.init(inst, def);
4668
- ZodType.init(inst, def);
4669
- inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
4670
- inst.keyType = def.keyType;
4671
- inst.valueType = def.valueType;
4672
- });
4673
- function record(keyType, valueType, params) {
4674
- return new ZodRecord({
4675
- type: "record",
4676
- keyType,
4677
- valueType,
4678
- ...exports_util.normalizeParams(params)
4679
- });
4680
- }
4681
4533
  var ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
4682
4534
  $ZodEnum.init(inst, def);
4683
4535
  ZodType.init(inst, def);
@@ -4724,27 +4576,6 @@ function _enum(values, params) {
4724
4576
  ...exports_util.normalizeParams(params)
4725
4577
  });
4726
4578
  }
4727
- var ZodLiteral = /* @__PURE__ */ $constructor("ZodLiteral", (inst, def) => {
4728
- $ZodLiteral.init(inst, def);
4729
- ZodType.init(inst, def);
4730
- inst._zod.processJSONSchema = (ctx, json, params) => literalProcessor(inst, ctx, json, params);
4731
- inst.values = new Set(def.values);
4732
- Object.defineProperty(inst, "value", {
4733
- get() {
4734
- if (def.values.length > 1) {
4735
- throw new Error("This schema contains multiple valid literal values. Use `.values` instead.");
4736
- }
4737
- return def.values[0];
4738
- }
4739
- });
4740
- });
4741
- function literal(value, params) {
4742
- return new ZodLiteral({
4743
- type: "literal",
4744
- values: Array.isArray(value) ? value : [value],
4745
- ...exports_util.normalizeParams(params)
4746
- });
4747
- }
4748
4579
  var ZodTransform = /* @__PURE__ */ $constructor("ZodTransform", (inst, def) => {
4749
4580
  $ZodTransform.init(inst, def);
4750
4581
  ZodType.init(inst, def);
@@ -4926,20 +4757,19 @@ var ContentsQuerySchema = object({
4926
4757
  });
4927
4758
  var ContentsItemSchema = object({
4928
4759
  url: string2().describe("URL"),
4929
- title: string2().optional().describe("Title"),
4930
- html: string2().optional().describe("HTML content"),
4931
- markdown: string2().optional().describe("Markdown content"),
4760
+ title: string2().optional().describe("Title (optional in actual API responses)"),
4761
+ html: string2().nullable().optional().describe("HTML content"),
4762
+ markdown: string2().nullable().optional().describe("Markdown content"),
4932
4763
  metadata: object({
4933
- jsonld: array(record(string2(), unknown())).optional().describe("JSON-LD structured data (Schema.org)"),
4934
- opengraph: record(string2(), string2()).optional().describe("OpenGraph meta tags"),
4935
- twitter: record(string2(), string2()).optional().describe("Twitter Card metadata")
4936
- }).optional().describe("Structured metadata when available")
4764
+ site_name: string2().nullable().optional().describe("OpenGraph site name"),
4765
+ favicon_url: string2().describe("Favicon URL")
4766
+ }).nullable().optional().describe("Page metadata (only when metadata format requested)")
4937
4767
  });
4938
4768
  var ContentsApiResponseSchema = array(ContentsItemSchema);
4939
4769
 
4940
4770
  // src/shared/api.constants.ts
4941
4771
  var SEARCH_API_URL = "https://ydc-index.io/v1/search";
4942
- var EXPRESS_API_URL = "https://api.you.com/v1/agents/runs";
4772
+ var DEEP_SEARCH_API_URL = "https://api.you.com/v1/deep_search";
4943
4773
  var CONTENTS_API_URL = "https://ydc-index.io/v1/contents";
4944
4774
 
4945
4775
  // src/shared/check-response-for-errors.ts
@@ -5007,199 +4837,101 @@ var fetchContents = async ({
5007
4837
  return parsedResults;
5008
4838
  };
5009
4839
 
5010
- // src/shared/use-get-user-agents.ts
5011
- var useGetUserAgent = (client = "") => () => `CLI/ ${package_default.version} (You.com;${client})`;
5012
-
5013
- // src/commands/contents.ts
5014
- var contentsCommand = async (args) => {
5015
- if (args.includes("--schema")) {
5016
- console.log(JSON.stringify(toJSONSchema(ContentsQuerySchema)));
5017
- process.exit(0);
5018
- }
5019
- const { values } = parseArgs({
5020
- args,
5021
- options: {
5022
- json: { type: "string" },
5023
- "api-key": { type: "string" },
5024
- client: { type: "string" }
5025
- }
5026
- });
5027
- if (!values.json) {
5028
- throw new Error("--json flag is required");
5029
- }
5030
- const query = JSON.parse(values.json);
5031
- const apiKey = values["api-key"];
5032
- const client = values.client || process.env.YDC_CLIENT;
5033
- const YDC_API_KEY = apiKey || process.env.YDC_API_KEY;
5034
- if (!YDC_API_KEY) {
5035
- throw new Error("YDC_API_KEY environment variable is required");
5036
- }
5037
- const contentsQuery = ContentsQuerySchema.parse(query);
5038
- const response = await fetchContents({
5039
- contentsQuery,
5040
- YDC_API_KEY,
5041
- getUserAgent: useGetUserAgent(client)
5042
- });
5043
- console.log(JSON.stringify(response));
5044
- };
5045
-
5046
- // src/commands/express.ts
5047
- import { parseArgs as parseArgs2 } from "node:util";
5048
-
5049
- // src/express/express.schemas.ts
5050
- var ExpressAgentInputSchema = object({
5051
- input: string2().min(1, "Input is required").describe("Query or prompt"),
5052
- tools: array(object({
5053
- type: _enum(["web_search"]).describe("Tool type")
5054
- })).optional().describe("Tools (web search only)")
5055
- });
5056
- var ApiSearchResultItemSchema = object({
5057
- source_type: string2().nullable().optional(),
5058
- citation_uri: string2().optional(),
5059
- url: string2(),
5060
- title: string2(),
5061
- snippet: string2(),
5062
- thumbnail_url: string2().nullable().optional(),
5063
- provider: string2().nullable().optional()
4840
+ // src/deep-search/deep-search.schemas.ts
4841
+ var SearchEffortSchema = _enum(["low", "medium", "high"]).describe("Search effort level");
4842
+ var DeepSearchQuerySchema = object({
4843
+ query: string2().min(1, "Query is required").describe("The research question or complex query requiring in-depth investigation and multi-step reasoning"),
4844
+ search_effort: SearchEffortSchema.optional().default("medium").describe("Computation budget: low (<30s), medium (<60s, default), high (<300s)")
5064
4845
  });
5065
- var ExpressAgentApiOutputItemSchema = union([
5066
- object({
5067
- type: literal("web_search.results"),
5068
- content: array(ApiSearchResultItemSchema)
5069
- }),
5070
- object({
5071
- type: literal("message.answer"),
5072
- text: string2()
5073
- })
5074
- ]);
5075
- var ExpressAgentApiResponseSchema = object({
5076
- output: array(ExpressAgentApiOutputItemSchema),
5077
- agent: string2().optional().describe("Agent identifier"),
5078
- mode: string2().optional().describe("Agent mode"),
5079
- input: array(object({
5080
- role: _enum(["user"]).describe("User role"),
5081
- content: string2().describe("User question")
5082
- })).optional().describe("Input messages")
5083
- }).passthrough();
5084
- var McpSearchResultItemSchema = object({
5085
- url: string2().describe("URL"),
5086
- title: string2().describe("Title"),
5087
- snippet: string2().describe("Snippet")
4846
+ var DeepSearchSourceSchema = object({
4847
+ url: string2().describe("Source webpage URL"),
4848
+ title: string2().describe("Source webpage title"),
4849
+ snippets: array(string2()).describe("Relevant excerpts from the source page used in generating the answer")
5088
4850
  });
5089
- var ExpressAgentMcpResponseSchema = object({
5090
- answer: string2().describe("AI answer"),
5091
- results: object({
5092
- web: array(McpSearchResultItemSchema).describe("Web results")
5093
- }).optional().describe("Search results"),
5094
- agent: string2().optional().describe("Agent ID")
4851
+ var DeepSearchResponseSchema = object({
4852
+ answer: string2().describe("Comprehensive response with inline citations, formatted in Markdown"),
4853
+ results: array(DeepSearchSourceSchema).describe("List of web sources used to generate the answer")
5095
4854
  });
5096
4855
 
5097
- // src/express/express.utils.ts
5098
- var agentThrowOnFailedStatus = async (response) => {
5099
- const errorCode = response.status;
5100
- const errorData = await response.json();
5101
- if (errorCode === 400) {
5102
- throw new Error(`Bad Request:
5103
- ${JSON.stringify(errorData)}`);
5104
- } else if (errorCode === 401) {
5105
- throw new Error(`Unauthorized: The Agent APIs require a valid You.com API key with agent access. Ensure your YDC_API_KEY has permissions for agent endpoints.`);
5106
- } else if (errorCode === 403) {
5107
- throw new Error(`Forbidden: You are not allowed to use the requested tool for this agent or tenant`);
5108
- } else if (errorCode === 429) {
5109
- throw new Error("Rate limited by You.com API. Please try again later.");
5110
- }
5111
- throw new Error(`Failed to call agent. Error code: ${errorCode}`);
5112
- };
5113
- var callExpressAgent = async ({
4856
+ // src/deep-search/deep-search.utils.ts
4857
+ var callDeepSearch = async ({
4858
+ deepSearchQuery,
5114
4859
  YDC_API_KEY = process.env.YDC_API_KEY,
5115
- agentInput: { input, tools },
5116
4860
  getUserAgent
5117
4861
  }) => {
5118
- const requestBody = {
5119
- agent: "express",
5120
- input,
5121
- stream: false
5122
- };
5123
- if (tools) {
5124
- requestBody.tools = tools;
4862
+ if (!YDC_API_KEY) {
4863
+ throw new Error("YDC_API_KEY is required for Deep Search API");
5125
4864
  }
5126
- const options = {
4865
+ const response = await fetch(DEEP_SEARCH_API_URL, {
5127
4866
  method: "POST",
5128
4867
  headers: new Headers({
5129
- Authorization: `Bearer ${YDC_API_KEY || ""}`,
4868
+ "X-API-Key": YDC_API_KEY,
5130
4869
  "Content-Type": "application/json",
5131
- Accept: "application/json",
5132
4870
  "User-Agent": getUserAgent()
5133
4871
  }),
5134
- body: JSON.stringify(requestBody)
5135
- };
5136
- const response = await fetch(EXPRESS_API_URL, options);
5137
- if (!response.ok) {
5138
- await agentThrowOnFailedStatus(response);
5139
- }
5140
- const jsonResponse = await response.json();
5141
- checkResponseForErrors(jsonResponse);
5142
- const apiResponse = ExpressAgentApiResponseSchema.parse(jsonResponse);
5143
- const answerItem = apiResponse.output.find((item) => item.type === "message.answer");
5144
- if (!answerItem) {
5145
- throw new Error("Express API response missing required message.answer item");
5146
- }
5147
- const searchItem = apiResponse.output.find((item) => item.type === "web_search.results");
5148
- const mcpResponse = {
5149
- answer: answerItem.text,
5150
- agent: apiResponse.agent
5151
- };
5152
- if (searchItem && "content" in searchItem && Array.isArray(searchItem.content)) {
5153
- mcpResponse.results = {
5154
- web: searchItem.content.map((item) => ({
5155
- url: item.url || item.citation_uri || "",
5156
- title: item.title || "",
5157
- snippet: item.snippet || ""
5158
- }))
5159
- };
5160
- }
5161
- return mcpResponse;
5162
- };
5163
-
5164
- // src/commands/express.ts
5165
- var expressCommand = async (args) => {
5166
- if (args.includes("--schema")) {
5167
- console.log(JSON.stringify(toJSONSchema(ExpressAgentInputSchema)));
5168
- process.exit(0);
5169
- }
5170
- const { values } = parseArgs2({
5171
- args,
5172
- options: {
5173
- json: { type: "string" },
5174
- "api-key": { type: "string" },
5175
- client: { type: "string" }
5176
- }
5177
- });
5178
- if (!values.json) {
5179
- throw new Error("--json flag is required");
5180
- }
5181
- const input = JSON.parse(values.json);
5182
- const apiKey = values["api-key"];
5183
- const client = values.client || process.env.YDC_CLIENT;
5184
- const YDC_API_KEY = apiKey || process.env.YDC_API_KEY;
5185
- if (!YDC_API_KEY) {
5186
- throw new Error("YDC_API_KEY environment variable is required");
5187
- }
5188
- const agentInput = ExpressAgentInputSchema.parse(input);
5189
- const response = await callExpressAgent({
5190
- agentInput,
5191
- YDC_API_KEY,
5192
- getUserAgent: useGetUserAgent(client)
4872
+ body: JSON.stringify(deepSearchQuery)
5193
4873
  });
5194
- console.log(JSON.stringify(response));
4874
+ await checkResponseForErrors(response);
4875
+ const data = await response.json();
4876
+ return DeepSearchResponseSchema.parse(data);
5195
4877
  };
5196
4878
 
5197
- // src/commands/search.ts
5198
- import { parseArgs as parseArgs3 } from "node:util";
5199
-
5200
4879
  // src/search/search.schemas.ts
4880
+ var LanguageSchema = _enum([
4881
+ "AR",
4882
+ "EU",
4883
+ "BN",
4884
+ "BG",
4885
+ "CA",
4886
+ "ZH-HANS",
4887
+ "ZH-HANT",
4888
+ "HR",
4889
+ "CS",
4890
+ "DA",
4891
+ "NL",
4892
+ "EN",
4893
+ "EN-GB",
4894
+ "ET",
4895
+ "FI",
4896
+ "FR",
4897
+ "GL",
4898
+ "DE",
4899
+ "EL",
4900
+ "GU",
4901
+ "HE",
4902
+ "HI",
4903
+ "HU",
4904
+ "IS",
4905
+ "IT",
4906
+ "JP",
4907
+ "KN",
4908
+ "KO",
4909
+ "LV",
4910
+ "LT",
4911
+ "MS",
4912
+ "ML",
4913
+ "MR",
4914
+ "NB",
4915
+ "PL",
4916
+ "PT-BR",
4917
+ "PT-PT",
4918
+ "PA",
4919
+ "RO",
4920
+ "RU",
4921
+ "SR",
4922
+ "SK",
4923
+ "SL",
4924
+ "ES",
4925
+ "SV",
4926
+ "TA",
4927
+ "TE",
4928
+ "TH",
4929
+ "TR",
4930
+ "UK",
4931
+ "VI"
4932
+ ]);
5201
4933
  var SearchQuerySchema = object({
5202
- query: string2().min(1, "Query is required").describe("Search query (supports +, -, site:, filetype:, lang:)"),
4934
+ query: string2().min(1, "Query is required").describe('Search query. Supports operators: site:domain.com (domain filter), filetype:pdf (file type), +term (include), -term (exclude), AND/OR/NOT (boolean logic), lang:en (language). Example: "machine learning (Python OR PyTorch) -TensorFlow filetype:pdf"'),
5203
4935
  count: number2().int().min(1).max(100).optional().describe("Max results per section"),
5204
4936
  freshness: string2().optional().describe("day/week/month/year or YYYY-MM-DDtoYYYY-MM-DD"),
5205
4937
  offset: number2().int().min(0).max(9).optional().describe("Pagination offset"),
@@ -5229,6 +4961,7 @@ var SearchQuerySchema = object({
5229
4961
  "CN",
5230
4962
  "PL",
5231
4963
  "PT",
4964
+ "PT-BR",
5232
4965
  "PH",
5233
4966
  "RU",
5234
4967
  "SA",
@@ -5242,11 +4975,6 @@ var SearchQuerySchema = object({
5242
4975
  "US"
5243
4976
  ]).optional().describe("Country code"),
5244
4977
  safesearch: _enum(["off", "moderate", "strict"]).optional().describe("Filter level"),
5245
- site: string2().optional().describe("Specific domain"),
5246
- fileType: string2().optional().describe("File type"),
5247
- language: string2().optional().describe("ISO 639-1 language code"),
5248
- excludeTerms: string2().optional().describe("Terms to exclude (pipe-separated)"),
5249
- exactTerms: string2().optional().describe("Exact terms (pipe-separated)"),
5250
4978
  livecrawl: _enum(["web", "news", "all"]).optional().describe("Live-crawl sections for full content"),
5251
4979
  livecrawl_formats: _enum(["html", "markdown"]).optional().describe("Format for crawled content")
5252
4980
  });
@@ -5291,24 +5019,15 @@ var SearchResponseSchema = object({
5291
5019
  // src/search/search.utils.ts
5292
5020
  var fetchSearchResults = async ({
5293
5021
  YDC_API_KEY = process.env.YDC_API_KEY,
5294
- searchQuery: { query, site, fileType, language, exactTerms, excludeTerms, ...rest },
5022
+ searchQuery,
5295
5023
  getUserAgent
5296
5024
  }) => {
5297
5025
  const url = new URL(SEARCH_API_URL);
5298
5026
  const searchParams = new URLSearchParams;
5299
- const searchQuery = [query];
5300
- site && searchQuery.push(`site:${site}`);
5301
- fileType && searchQuery.push(`filetype:${fileType}`);
5302
- language && searchQuery.push(`lang:${language}`);
5303
- if (exactTerms && excludeTerms) {
5304
- throw new Error("Cannot specify both exactTerms and excludeTerms - please use only one");
5305
- }
5306
- exactTerms && searchQuery.push(exactTerms.split("|").map((term) => `+${term}`).join(" AND "));
5307
- excludeTerms && searchQuery.push(excludeTerms.split("|").map((term) => `-${term}`).join(" AND "));
5308
- searchParams.append("query", searchQuery.join(" "));
5309
- for (const [name, value] of Object.entries(rest)) {
5310
- if (value)
5027
+ for (const [name, value] of Object.entries(searchQuery)) {
5028
+ if (value !== undefined && value !== null) {
5311
5029
  searchParams.append(name, `${value}`);
5030
+ }
5312
5031
  }
5313
5032
  url.search = searchParams.toString();
5314
5033
  const options = {
@@ -5334,39 +5053,119 @@ var fetchSearchResults = async ({
5334
5053
  return parsedResults;
5335
5054
  };
5336
5055
 
5337
- // src/commands/search.ts
5338
- var searchCommand = async (args) => {
5056
+ // src/shared/command-runner.ts
5057
+ import { parseArgs } from "node:util";
5058
+
5059
+ // src/shared/use-get-user-agents.ts
5060
+ var useGetUserAgent = (client = "") => () => `CLI/${package_default.version}(You.com;${client})`;
5061
+
5062
+ // src/shared/command-runner.ts
5063
+ var runCommand = async (args, config2) => {
5339
5064
  if (args.includes("--schema")) {
5340
- console.log(JSON.stringify(toJSONSchema(SearchQuerySchema)));
5065
+ console.log(JSON.stringify(toJSONSchema(config2.schema)));
5341
5066
  process.exit(0);
5342
5067
  }
5343
- const { values } = parseArgs3({
5068
+ const { values } = parseArgs({
5344
5069
  args,
5345
5070
  options: {
5346
5071
  json: { type: "string" },
5347
5072
  "api-key": { type: "string" },
5348
- client: { type: "string" }
5073
+ client: { type: "string" },
5074
+ "dry-run": { type: "boolean" }
5349
5075
  }
5350
5076
  });
5351
5077
  if (!values.json) {
5352
5078
  throw new Error("--json flag is required");
5353
5079
  }
5354
- const query = JSON.parse(values.json);
5080
+ const input = JSON.parse(values.json);
5355
5081
  const apiKey = values["api-key"];
5356
5082
  const client = values.client || process.env.YDC_CLIENT;
5357
5083
  const YDC_API_KEY = apiKey || process.env.YDC_API_KEY;
5358
5084
  if (!YDC_API_KEY) {
5359
5085
  throw new Error("YDC_API_KEY environment variable is required");
5360
5086
  }
5361
- const searchQuery = SearchQuerySchema.parse(query);
5362
- const response = await fetchSearchResults({
5363
- searchQuery,
5087
+ const validatedInput = config2.schema.parse(input);
5088
+ const getUserAgent = useGetUserAgent(client);
5089
+ if (values["dry-run"] && config2.dryRunHandler) {
5090
+ const dryRunResult = config2.dryRunHandler({
5091
+ input: validatedInput,
5092
+ YDC_API_KEY,
5093
+ getUserAgent
5094
+ });
5095
+ console.log(JSON.stringify(dryRunResult));
5096
+ return;
5097
+ }
5098
+ const response = await config2.handler({
5099
+ input: validatedInput,
5364
5100
  YDC_API_KEY,
5365
- getUserAgent: useGetUserAgent(client)
5101
+ getUserAgent
5366
5102
  });
5367
5103
  console.log(JSON.stringify(response));
5368
5104
  };
5369
5105
 
5106
+ // src/shared/dry-run-utils.ts
5107
+ var buildSearchRequest = ({
5108
+ searchQuery,
5109
+ YDC_API_KEY,
5110
+ getUserAgent
5111
+ }) => {
5112
+ const queryParams = {};
5113
+ for (const [name, value] of Object.entries(searchQuery)) {
5114
+ if (value !== undefined && value !== null) {
5115
+ queryParams[name] = `${value}`;
5116
+ }
5117
+ }
5118
+ return {
5119
+ url: SEARCH_API_URL,
5120
+ method: "GET",
5121
+ headers: {
5122
+ "X-API-Key": YDC_API_KEY,
5123
+ "User-Agent": getUserAgent()
5124
+ },
5125
+ queryParams
5126
+ };
5127
+ };
5128
+ var buildContentsRequest = ({
5129
+ contentsQuery: { urls, formats, format, crawl_timeout },
5130
+ YDC_API_KEY,
5131
+ getUserAgent
5132
+ }) => {
5133
+ const requestFormats = formats || (format ? [format] : ["markdown"]);
5134
+ const requestBody = {
5135
+ urls,
5136
+ formats: requestFormats
5137
+ };
5138
+ if (crawl_timeout !== undefined) {
5139
+ requestBody.crawl_timeout = crawl_timeout;
5140
+ }
5141
+ return {
5142
+ url: CONTENTS_API_URL,
5143
+ method: "POST",
5144
+ headers: {
5145
+ "X-API-Key": YDC_API_KEY,
5146
+ "Content-Type": "application/json",
5147
+ "User-Agent": getUserAgent()
5148
+ },
5149
+ body: JSON.stringify(requestBody)
5150
+ };
5151
+ };
5152
+ var buildDeepSearchRequest = ({
5153
+ deepSearchQuery,
5154
+ YDC_API_KEY,
5155
+ getUserAgent
5156
+ }) => {
5157
+ return {
5158
+ url: DEEP_SEARCH_API_URL,
5159
+ method: "POST",
5160
+ headers: {
5161
+ "X-API-Key": YDC_API_KEY,
5162
+ "Content-Type": "application/json",
5163
+ "User-Agent": getUserAgent()
5164
+ },
5165
+ body: JSON.stringify(deepSearchQuery)
5166
+ };
5167
+ };
5168
+
5370
5169
  // src/shared/generate-error-report-link.ts
5371
5170
  var generateErrorReportLink = ({
5372
5171
  errorMessage,
@@ -5406,7 +5205,7 @@ Usage: ydc <command> --json <json> [options]
5406
5205
 
5407
5206
  Commands:
5408
5207
  search Search the web with You.com
5409
- express Get AI answers with web context
5208
+ deep-search Perform deep research with comprehensive answers
5410
5209
  contents Extract content from URLs
5411
5210
 
5412
5211
  Global Options:
@@ -5414,6 +5213,7 @@ Global Options:
5414
5213
  --api-key <key> You.com API key (overrides YDC_API_KEY)
5415
5214
  --client <name> Client name for tracking and debugging
5416
5215
  --schema Output JSON schema for what can be passed to --json
5216
+ --dry-run Show request details without making API call
5417
5217
  --help, -h Show this help
5418
5218
 
5419
5219
  Environment Variables:
@@ -5426,36 +5226,69 @@ Output Format:
5426
5226
 
5427
5227
  Examples:
5428
5228
  ydc search --json '{"query":"AI developments"}' --client Openclaw
5429
- ydc express --json '{"input":"What happened today?","tools":[{"type":"web_search"}]}' --client MyAgent
5229
+ ydc deep-search --json '{"query":"What are the latest breakthroughs in AI?","search_effort":"high"}' --client MyAgent
5430
5230
  ydc contents --json '{"urls":["https://example.com"],"formats":["markdown"]}'
5431
5231
  ydc search --schema # Get JSON schema for search --json input
5232
+ ydc search --json '{"query":"AI"}' --dry-run # Inspect request without API call
5432
5233
  ydc search --json '{"query":"AI"}' | jq '.data.results.web[0].title'
5433
5234
 
5434
5235
  More info: https://github.com/youdotcom-oss/dx-toolkit/tree/main/packages/api
5435
5236
  `);
5436
5237
  process.exit(command ? 0 : 2);
5437
5238
  }
5438
- try {
5439
- switch (command) {
5440
- case "search":
5441
- await searchCommand(args);
5442
- break;
5443
- case "express":
5444
- await expressCommand(args);
5445
- break;
5446
- case "contents":
5447
- await contentsCommand(args);
5448
- break;
5449
- default:
5450
- console.error(`Unknown command: ${command}`);
5451
- console.error(`Run 'ydc --help' for usage`);
5452
- process.exit(2);
5239
+ var commands = {
5240
+ search: {
5241
+ schema: SearchQuerySchema,
5242
+ handler: ({
5243
+ input,
5244
+ YDC_API_KEY,
5245
+ getUserAgent
5246
+ }) => fetchSearchResults({ searchQuery: input, YDC_API_KEY, getUserAgent }),
5247
+ dryRunHandler: ({
5248
+ input,
5249
+ YDC_API_KEY,
5250
+ getUserAgent
5251
+ }) => buildSearchRequest({ searchQuery: input, YDC_API_KEY, getUserAgent })
5252
+ },
5253
+ "deep-search": {
5254
+ schema: DeepSearchQuerySchema,
5255
+ handler: ({
5256
+ input,
5257
+ YDC_API_KEY,
5258
+ getUserAgent
5259
+ }) => callDeepSearch({ deepSearchQuery: input, YDC_API_KEY, getUserAgent }),
5260
+ dryRunHandler: ({
5261
+ input,
5262
+ YDC_API_KEY,
5263
+ getUserAgent
5264
+ }) => buildDeepSearchRequest({ deepSearchQuery: input, YDC_API_KEY, getUserAgent })
5265
+ },
5266
+ contents: {
5267
+ schema: ContentsQuerySchema,
5268
+ handler: ({
5269
+ input,
5270
+ YDC_API_KEY,
5271
+ getUserAgent
5272
+ }) => fetchContents({ contentsQuery: input, YDC_API_KEY, getUserAgent }),
5273
+ dryRunHandler: ({
5274
+ input,
5275
+ YDC_API_KEY,
5276
+ getUserAgent
5277
+ }) => buildContentsRequest({ contentsQuery: input, YDC_API_KEY, getUserAgent })
5453
5278
  }
5279
+ };
5280
+ if (!(command in commands)) {
5281
+ console.error(`Unknown command: ${command}`);
5282
+ console.error(`Run 'ydc --help' for usage`);
5283
+ process.exit(2);
5284
+ }
5285
+ try {
5286
+ await runCommand(args, commands[command]);
5454
5287
  process.exit(0);
5455
5288
  } catch (error2) {
5456
5289
  console.error(error2);
5457
5290
  const message = error2 instanceof Error ? error2.message : String(error2);
5458
- const { values } = parseArgs4({
5291
+ const { values } = parseArgs2({
5459
5292
  args,
5460
5293
  options: {
5461
5294
  client: { type: "string" }