@kweaver-ai/kweaver-sdk 0.6.10 → 0.7.2

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.
@@ -1,22 +1,85 @@
1
1
  import { ensureValidToken, formatHttpError, resolveActivePlatform, with401RefreshRetry } from "../auth/oauth.js";
2
- import { knSearch, knSchemaSearch, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, listTools, listResources, readResource, listResourceTemplates, listPrompts, getPrompt, } from "../api/context-loader.js";
3
- import { addContextLoaderEntry, getCurrentContextLoaderKn, loadContextLoaderConfig, removeContextLoaderEntry, setCurrentContextLoader, } from "../config/store.js";
2
+ import { callTool, searchSchema, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, findSkills, listTools, listResources, readResource, listResourceTemplates, listPrompts, getPrompt, } from "../api/context-loader.js";
3
+ import { knSearchHttp, semanticSearch } from "../api/semantic-search.js";
4
+ import { addContextLoaderEntry, getCurrentContextLoaderKn, loadContextLoaderConfig, removeContextLoaderEntry, resolveBusinessDomain, setCurrentContextLoader, } from "../config/store.js";
5
+ import { assertNotStatelessForWrite } from "../config/stateless.js";
6
+ const CONTEXT_LOADER_CONFIG_DEPRECATION = "[deprecated] `kweaver context-loader config ...` will be removed in a future release. " +
7
+ "Pass <kn-id> as the first positional to runtime subcommands instead, e.g. " +
8
+ "`kweaver context-loader tools <kn-id>` (or use the `--kn-id <id>` flag).";
4
9
  const MCP_NOT_CONFIGURED = "Context-loader MCP is not configured. Run: kweaver context-loader config set --kn-id <kn-id>";
5
- function ensureContextLoaderConfig() {
10
+ const MCP_PATH = "/api/agent-retrieval/v1/mcp";
11
+ function ensureContextLoaderConfig(knIdOverride) {
6
12
  const active = resolveActivePlatform();
7
13
  if (!active) {
8
14
  throw new Error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
9
15
  }
16
+ // Override path (positional <kn-id> or --kn-id flag): derive MCP URL from
17
+ // the active platform; do not touch the deprecated saved config.
18
+ if (knIdOverride) {
19
+ return {
20
+ baseUrl: active.url,
21
+ mcpUrl: active.url.replace(/\/+$/, "") + MCP_PATH,
22
+ knId: knIdOverride,
23
+ accessToken: "",
24
+ businessDomain: resolveBusinessDomain(active.url),
25
+ };
26
+ }
10
27
  const kn = getCurrentContextLoaderKn();
11
28
  if (!kn) {
12
29
  throw new Error(MCP_NOT_CONFIGURED);
13
30
  }
14
31
  return {
32
+ baseUrl: active.url,
15
33
  mcpUrl: kn.mcpUrl,
16
34
  knId: kn.knId,
17
35
  accessToken: "", // filled by caller after ensureValidToken
36
+ businessDomain: resolveBusinessDomain(active.url),
18
37
  };
19
38
  }
39
+ // Subcommands that consult `ensureContextLoaderConfig`. The number is the
40
+ // minimum non-flag positional count expected by the handler itself (after
41
+ // kn-id is extracted). When the leading non-flag positional count exceeds
42
+ // this minimum, the first one is treated as <kn-id>.
43
+ const RUNTIME_MIN_POSITIONALS = {
44
+ tools: 0,
45
+ resources: 0,
46
+ templates: 0,
47
+ prompts: 0,
48
+ prompt: 1,
49
+ resource: 1,
50
+ "search-schema": 1,
51
+ "tool-call": 1,
52
+ "kn-search": 1,
53
+ "kn-schema-search": 1,
54
+ "query-object-instance": 1,
55
+ "query-instance-subgraph": 1,
56
+ "get-logic-properties": 1,
57
+ "get-action-info": 1,
58
+ "find-skills": 1,
59
+ };
60
+ function extractKnIdOverride(subcommand, rest) {
61
+ // 1) Explicit flag wins. `--kn-id <id>` / `-k <id>` is allowed for every
62
+ // runtime subcommand and is consumed before the handler sees `rest`.
63
+ for (let i = 0; i < rest.length; i += 1) {
64
+ if ((rest[i] === "--kn-id" || rest[i] === "-k") && rest[i + 1]) {
65
+ const id = rest[i + 1];
66
+ rest.splice(i, 2);
67
+ return id;
68
+ }
69
+ }
70
+ // 2) Positional <kn-id> as the first non-flag arg, when leading non-flag
71
+ // positional count exceeds what the handler itself requires.
72
+ const min = RUNTIME_MIN_POSITIONALS[subcommand];
73
+ if (min === undefined)
74
+ return undefined;
75
+ let cut = 0;
76
+ while (cut < rest.length && !rest[cut].startsWith("-"))
77
+ cut += 1;
78
+ if (cut > min) {
79
+ return rest.shift();
80
+ }
81
+ return undefined;
82
+ }
20
83
  function formatOutput(value, pretty) {
21
84
  const json = JSON.stringify(value, null, pretty ? 2 : 0);
22
85
  return json;
@@ -26,29 +89,38 @@ export async function runContextLoaderCommand(args) {
26
89
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
27
90
  console.log(`kweaver context-loader
28
91
 
92
+ KN selection (for runtime subcommands below):
93
+ Pass <kn-id> as the FIRST positional, e.g. \`kweaver context-loader tools <kn-id>\`,
94
+ or use the global \`--kn-id <id>\` / \`-k <id>\` flag. When omitted, falls back to
95
+ the deprecated saved config managed by \`kweaver context-loader config\`.
96
+
29
97
  Subcommands:
30
- config set --kn-id <id> [--name n] Add or update kn config (MCP URL derived from platform)
31
- config use <name> Switch current config
32
- config list List all configs and current
33
- config remove <name> Remove a config
34
- config show Show current config (knId + mcpUrl)
35
- tools tools/list - list available tools
36
- resources resources/list - list resources
37
- resource <uri> resources/read - read resource by URI
38
- templates resources/templates/list - list resource templates
39
- prompts prompts/list - list prompts
40
- prompt <name> [--args json] prompts/get - get prompt by name
41
- kn-search <query> [--only-schema] Layer 1: Search schema (object_types, relation_types, action_types)
42
- kn-schema-search <query> [--max N] Layer 1: Discover candidate concepts
43
- query-object-instance <json> Layer 2: Query instances (args as JSON)
44
- query-instance-subgraph <json> Layer 2: Query subgraph (args as JSON)
45
- get-logic-properties <json> Layer 3: Get logic property values (args as JSON)
46
- get-action-info <json> Layer 3: Get action info (args as JSON)
98
+ config set --kn-id <id> [--name n] [deprecated] Add or update kn config
99
+ config use <name> [deprecated] Switch current config
100
+ config list [deprecated] List all configs and current
101
+ config remove <name> [deprecated] Remove a config
102
+ config show [deprecated] Show current config (knId + mcpUrl)
103
+ tools <kn-id> tools/list - list available tools
104
+ resources <kn-id> resources/list - list resources
105
+ resource <kn-id> <uri> resources/read - read resource by URI
106
+ templates <kn-id> resources/templates/list - list resource templates
107
+ prompts <kn-id> prompts/list - list prompts
108
+ prompt <kn-id> <name> [--args json] prompts/get - get prompt by name
109
+ search-schema <kn-id> <query> [opts] MCP search_schema (object/relation/action/metric)
110
+ tool-call <kn-id> <name> --args '<json>' MCP tools/call for any server tool
111
+ kn-search <kn-id> <query> [--only-schema] Compatibility: HTTP kn_search
112
+ kn-schema-search <kn-id> <query> [--max N] Compatibility: HTTP semantic-search
113
+ query-object-instance <kn-id> <json> Layer 2: Query instances
114
+ query-instance-subgraph <kn-id> <json> Layer 2: Query subgraph
115
+ get-logic-properties <kn-id> <json> Layer 3: Get logic property values
116
+ get-action-info <kn-id> <json> Layer 3: Get action info
117
+ find-skills <kn-id> <ot_id> [options] Layer 3: Recall skills for an object type
47
118
 
48
119
  Examples:
49
- kweaver context-loader config set --kn-id d5iv6c9818p72mpje8pg
50
- kweaver context-loader config set --kn-id xyz123 --name project-a
51
- kweaver context-loader kn-search "高血压 治疗 药品" --only-schema --pretty`);
120
+ kweaver context-loader tools d5iv6c9818p72mpje8pg
121
+ kweaver context-loader search-schema d5iv6c9818p72mpje8pg "利润率" --scope object,metric --max 5
122
+ kweaver context-loader tool-call d5iv6c9818p72mpje8pg search_schema --args '{"query":"利润率"}'
123
+ kweaver context-loader kn-search d5iv6c9818p72mpje8pg "高血压 治疗 药品" --only-schema --pretty`);
52
124
  return 0;
53
125
  }
54
126
  if (subcommand === "config") {
@@ -60,9 +132,12 @@ Examples:
60
132
  pretty = true;
61
133
  rest.splice(prettyIdx, 1);
62
134
  }
135
+ // Extract `<kn-id>` (positional or --kn-id/-k flag) before per-subcommand
136
+ // arg parsing. When provided it bypasses the deprecated saved config.
137
+ const knIdOverride = extractKnIdOverride(subcommand, rest);
63
138
  const dispatch = async () => {
64
139
  const token = await ensureValidToken();
65
- const base = ensureContextLoaderConfig();
140
+ const base = ensureContextLoaderConfig(knIdOverride);
66
141
  const options = { ...base, accessToken: token.accessToken };
67
142
  if (subcommand === "tools")
68
143
  return runListTools(options, rest, pretty);
@@ -76,6 +151,10 @@ Examples:
76
151
  return runListPrompts(options, rest, pretty);
77
152
  if (subcommand === "prompt")
78
153
  return runGetPrompt(options, rest, pretty);
154
+ if (subcommand === "search-schema")
155
+ return runSearchSchema(options, rest, pretty);
156
+ if (subcommand === "tool-call")
157
+ return runToolCall(options, rest, pretty);
79
158
  if (subcommand === "kn-search")
80
159
  return runKnSearch(options, rest, pretty);
81
160
  if (subcommand === "kn-schema-search")
@@ -88,6 +167,8 @@ Examples:
88
167
  return runGetLogicProperties(options, rest, pretty);
89
168
  if (subcommand === "get-action-info")
90
169
  return runGetActionInfo(options, rest, pretty);
170
+ if (subcommand === "find-skills")
171
+ return runFindSkills(options, rest, pretty);
91
172
  return -1;
92
173
  };
93
174
  try {
@@ -108,16 +189,30 @@ Examples:
108
189
  async function runConfigCommand(args) {
109
190
  const [action, ...rest] = args;
110
191
  if (!action || action === "--help" || action === "-h") {
111
- console.log(`kweaver context-loader config
192
+ console.log(`kweaver context-loader config [deprecated]
112
193
 
113
194
  Subcommands:
114
195
  set --kn-id <id> [--name <name>] Add or update kn config (default name: default)
115
196
  use <name> Switch current config
116
197
  list List all configs and current
117
198
  remove <name> Remove a config
118
- show Show current config (knId + mcpUrl)`);
199
+ show Show current config (knId + mcpUrl)
200
+
201
+ Note: this command group is deprecated and will be removed in a future release.
202
+ It is disabled entirely in stateless mode (\`--token\`).`);
119
203
  return 0;
120
204
  }
205
+ // Stateless mode (`--token`) does not support any context-loader config
206
+ // operations; the saved config lives under `~/.kweaver/` and is foreign
207
+ // to the stateless paradigm.
208
+ try {
209
+ assertNotStatelessForWrite(`context-loader config ${action}`);
210
+ }
211
+ catch (err) {
212
+ console.error(err instanceof Error ? err.message : String(err));
213
+ return 1;
214
+ }
215
+ console.warn(CONTEXT_LOADER_CONFIG_DEPRECATION);
121
216
  const active = resolveActivePlatform();
122
217
  if (!active) {
123
218
  console.error("No platform selected. Set KWEAVER_BASE_URL or run: kweaver auth <platform-url>");
@@ -279,29 +374,170 @@ async function runGetPrompt(options, args, pretty) {
279
374
  console.log(formatOutput(result, pretty));
280
375
  return 0;
281
376
  }
377
+ function parseResponseText(text) {
378
+ try {
379
+ return JSON.parse(text);
380
+ }
381
+ catch {
382
+ return { raw: text };
383
+ }
384
+ }
385
+ function parseSearchSchemaScope(raw) {
386
+ const scope = {
387
+ include_object_types: false,
388
+ include_relation_types: false,
389
+ include_action_types: false,
390
+ include_metric_types: false,
391
+ };
392
+ const aliases = {
393
+ object: "include_object_types",
394
+ objects: "include_object_types",
395
+ object_type: "include_object_types",
396
+ object_types: "include_object_types",
397
+ relation: "include_relation_types",
398
+ relations: "include_relation_types",
399
+ relation_type: "include_relation_types",
400
+ relation_types: "include_relation_types",
401
+ action: "include_action_types",
402
+ actions: "include_action_types",
403
+ action_type: "include_action_types",
404
+ action_types: "include_action_types",
405
+ metric: "include_metric_types",
406
+ metrics: "include_metric_types",
407
+ metric_type: "include_metric_types",
408
+ metric_types: "include_metric_types",
409
+ };
410
+ for (const item of raw.split(",")) {
411
+ const key = item.trim().toLowerCase();
412
+ if (!key)
413
+ continue;
414
+ const field = aliases[key];
415
+ if (!field) {
416
+ throw new Error(`Invalid --scope value: ${item}`);
417
+ }
418
+ scope[field] = true;
419
+ }
420
+ return scope;
421
+ }
422
+ async function runSearchSchema(options, args, pretty) {
423
+ let query;
424
+ let responseFormat;
425
+ let searchScope;
426
+ let maxConcepts;
427
+ let schemaBrief;
428
+ let enableRerank;
429
+ for (let i = 0; i < args.length; i += 1) {
430
+ const arg = args[i];
431
+ if ((arg === "--format" || arg === "-f") && args[i + 1]) {
432
+ const value = args[i + 1];
433
+ if (value !== "json" && value !== "toon") {
434
+ console.error("Usage: kweaver context-loader search-schema <query> [--format json|toon] [--scope object,relation,action,metric] [--max N] [--brief] [--no-rerank]");
435
+ return 1;
436
+ }
437
+ responseFormat = value;
438
+ i += 1;
439
+ }
440
+ else if ((arg === "--scope" || arg === "-s") && args[i + 1]) {
441
+ try {
442
+ searchScope = parseSearchSchemaScope(args[i + 1]);
443
+ }
444
+ catch (error) {
445
+ console.error(error instanceof Error ? error.message : String(error));
446
+ return 1;
447
+ }
448
+ i += 1;
449
+ }
450
+ else if ((arg === "--max" || arg === "-n") && args[i + 1]) {
451
+ maxConcepts = parseInt(args[i + 1], 10);
452
+ if (!Number.isFinite(maxConcepts)) {
453
+ console.error("Usage: kweaver context-loader search-schema <query> [--max N]");
454
+ return 1;
455
+ }
456
+ i += 1;
457
+ }
458
+ else if (arg === "--brief") {
459
+ schemaBrief = true;
460
+ }
461
+ else if (arg === "--no-rerank") {
462
+ enableRerank = false;
463
+ }
464
+ else if (!arg.startsWith("-") && !query) {
465
+ query = arg;
466
+ }
467
+ }
468
+ if (!query) {
469
+ console.error("Usage: kweaver context-loader search-schema <query> [--format json|toon] [--scope object,relation,action,metric] [--max N] [--brief] [--no-rerank]");
470
+ return 1;
471
+ }
472
+ const result = await searchSchema(options, {
473
+ query,
474
+ response_format: responseFormat,
475
+ search_scope: searchScope,
476
+ max_concepts: maxConcepts,
477
+ schema_brief: schemaBrief,
478
+ enable_rerank: enableRerank,
479
+ });
480
+ console.log(formatOutput(result, pretty));
481
+ return 0;
482
+ }
483
+ async function runToolCall(options, args, pretty) {
484
+ let toolName;
485
+ let rawArgs;
486
+ for (let i = 0; i < args.length; i += 1) {
487
+ const arg = args[i];
488
+ if ((arg === "--args" || arg === "-a") && args[i + 1]) {
489
+ rawArgs = args[i + 1];
490
+ i += 1;
491
+ }
492
+ else if (!arg.startsWith("-") && !toolName) {
493
+ toolName = arg;
494
+ }
495
+ }
496
+ if (!toolName || rawArgs === undefined) {
497
+ console.error("Usage: kweaver context-loader tool-call <name> --args '<json>'");
498
+ return 1;
499
+ }
500
+ let parsedArgs;
501
+ try {
502
+ parsedArgs = JSON.parse(rawArgs);
503
+ }
504
+ catch {
505
+ console.error("Invalid --args JSON");
506
+ return 1;
507
+ }
508
+ if (parsedArgs === null || typeof parsedArgs !== "object" || Array.isArray(parsedArgs)) {
509
+ console.error("--args must be a JSON object");
510
+ return 1;
511
+ }
512
+ const result = await callTool(options, toolName, parsedArgs);
513
+ console.log(formatOutput(result, pretty));
514
+ return 0;
515
+ }
282
516
  async function runKnSearch(options, args, pretty) {
283
517
  let query;
284
518
  let onlySchema = false;
285
- let knIdOverride;
286
519
  for (let i = 0; i < args.length; i += 1) {
287
520
  const arg = args[i];
288
521
  if (arg === "--only-schema") {
289
522
  onlySchema = true;
290
523
  }
291
- else if ((arg === "--kn-id" || arg === "-k") && args[i + 1]) {
292
- knIdOverride = args[i + 1];
293
- i += 1;
294
- }
295
524
  else if (!arg.startsWith("-") && !query) {
296
525
  query = arg;
297
526
  }
298
527
  }
299
528
  if (!query) {
300
- console.error("Usage: kweaver context-loader kn-search <query> [--kn-id <id>] [--only-schema]");
529
+ console.error("Usage: kweaver context-loader kn-search <kn-id> <query> [--only-schema]");
301
530
  return 1;
302
531
  }
303
- const effectiveOptions = knIdOverride ? { ...options, knId: knIdOverride } : options;
304
- const result = await knSearch(effectiveOptions, { query, only_schema: onlySchema });
532
+ const raw = await knSearchHttp({
533
+ baseUrl: options.baseUrl,
534
+ accessToken: options.accessToken,
535
+ businessDomain: options.businessDomain,
536
+ knId: options.knId,
537
+ query,
538
+ onlySchema,
539
+ });
540
+ const result = parseResponseText(raw);
305
541
  console.log(formatOutput(result, pretty));
306
542
  return 0;
307
543
  }
@@ -322,10 +558,15 @@ async function runKnSchemaSearch(options, args, pretty) {
322
558
  console.error("Usage: kweaver context-loader kn-schema-search <query> [--max N]");
323
559
  return 1;
324
560
  }
325
- const result = await knSchemaSearch(options, {
561
+ const raw = await semanticSearch({
562
+ baseUrl: options.baseUrl,
563
+ accessToken: options.accessToken,
564
+ businessDomain: options.businessDomain,
565
+ knId: options.knId,
326
566
  query,
327
- max_concepts: maxConcepts,
567
+ maxConcepts,
328
568
  });
569
+ const result = parseResponseText(raw);
329
570
  console.log(formatOutput(result, pretty));
330
571
  return 0;
331
572
  }
@@ -385,3 +626,66 @@ async function runGetActionInfo(options, args, pretty) {
385
626
  console.log(formatOutput(result, pretty));
386
627
  return 0;
387
628
  }
629
+ async function runFindSkills(options, args, pretty) {
630
+ const usage = "Usage: kweaver context-loader find-skills <object_type_id> " +
631
+ "[--query <text>] [--top-k N] [--instance-identities <json>] [--format json|toon]";
632
+ let objectTypeId;
633
+ let skillQuery;
634
+ let topK;
635
+ let instanceIdentities;
636
+ let responseFormat;
637
+ for (let i = 0; i < args.length; i += 1) {
638
+ const arg = args[i];
639
+ if ((arg === "--query" || arg === "-q") && args[i + 1]) {
640
+ skillQuery = args[i + 1];
641
+ i += 1;
642
+ }
643
+ else if ((arg === "--top-k" || arg === "-n") && args[i + 1]) {
644
+ topK = parseInt(args[i + 1], 10);
645
+ if (!Number.isFinite(topK)) {
646
+ console.error(usage);
647
+ return 1;
648
+ }
649
+ i += 1;
650
+ }
651
+ else if ((arg === "--instance-identities" || arg === "-i") && args[i + 1]) {
652
+ try {
653
+ const parsed = JSON.parse(args[i + 1]);
654
+ if (!Array.isArray(parsed)) {
655
+ throw new Error("--instance-identities must be a JSON array");
656
+ }
657
+ instanceIdentities = parsed;
658
+ }
659
+ catch (error) {
660
+ console.error(error instanceof Error ? error.message : String(error));
661
+ return 1;
662
+ }
663
+ i += 1;
664
+ }
665
+ else if ((arg === "--format" || arg === "-f") && args[i + 1]) {
666
+ const value = args[i + 1];
667
+ if (value !== "json" && value !== "toon") {
668
+ console.error(usage);
669
+ return 1;
670
+ }
671
+ responseFormat = value;
672
+ i += 1;
673
+ }
674
+ else if (!arg.startsWith("-") && !objectTypeId) {
675
+ objectTypeId = arg;
676
+ }
677
+ }
678
+ if (!objectTypeId) {
679
+ console.error(usage);
680
+ return 1;
681
+ }
682
+ const result = await findSkills(options, {
683
+ object_type_id: objectTypeId,
684
+ skill_query: skillQuery,
685
+ top_k: topK,
686
+ instance_identities: instanceIdentities,
687
+ response_format: responseFormat,
688
+ });
689
+ console.log(formatOutput(result, pretty));
690
+ return 0;
691
+ }
@@ -5,6 +5,29 @@ export declare function parseDsListArgs(args: string[]): {
5
5
  businessDomain: string;
6
6
  pretty: boolean;
7
7
  };
8
+ /**
9
+ * Match candidate signature against a list response (the kind returned by
10
+ * `listDatasources`). Connection metadata lives under `bin_data` — host,
11
+ * port, account, plus type-specific fields (`database_name` for MySQL etc.).
12
+ *
13
+ * Exported for unit testing.
14
+ */
15
+ export interface DsMatchSignature {
16
+ type: string;
17
+ host: string;
18
+ port: number;
19
+ database: string;
20
+ account: string;
21
+ name?: string;
22
+ }
23
+ export interface DsMatchHit {
24
+ id: string;
25
+ name: string;
26
+ matchedByName: boolean;
27
+ matchedByTuple: boolean;
28
+ }
29
+ export declare function findExistingDatasource(listBody: string, sig: DsMatchSignature): DsMatchHit | undefined;
30
+ export declare function findDatasourceIdByName(listBody: string, name: string): string | undefined;
8
31
  export declare function parseImportCsvArgs(args: string[]): {
9
32
  datasourceId: string;
10
33
  files: string;