@kweaver-ai/kweaver-sdk 0.7.4 → 0.8.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 (56) hide show
  1. package/README.md +20 -0
  2. package/README.zh.md +18 -0
  3. package/dist/api/agent-observability.d.ts +51 -0
  4. package/dist/api/agent-observability.js +108 -0
  5. package/dist/api/conversations.d.ts +4 -8
  6. package/dist/api/conversations.js +16 -58
  7. package/dist/api/datasources.d.ts +2 -20
  8. package/dist/api/datasources.js +7 -123
  9. package/dist/api/trace.d.ts +44 -0
  10. package/dist/api/trace.js +81 -0
  11. package/dist/api/vega.d.ts +53 -0
  12. package/dist/api/vega.js +144 -0
  13. package/dist/cli.js +5 -0
  14. package/dist/commands/bkn-ops.js +12 -6
  15. package/dist/commands/bkn-utils.d.ts +9 -0
  16. package/dist/commands/bkn-utils.js +17 -0
  17. package/dist/commands/ds.js +7 -2
  18. package/dist/commands/trace.d.ts +14 -0
  19. package/dist/commands/trace.js +168 -0
  20. package/dist/resources/datasources.js +2 -1
  21. package/dist/trace-core/diagnose/builtin-rules/excessive-tool-calls-per-turn.d.ts +2 -0
  22. package/dist/trace-core/diagnose/builtin-rules/excessive-tool-calls-per-turn.js +15 -0
  23. package/dist/trace-core/diagnose/builtin-rules/excessive-tool-calls-per-turn.yaml +16 -0
  24. package/dist/trace-core/diagnose/builtin-rules/llm-response-truncated-no-continue.d.ts +2 -0
  25. package/dist/trace-core/diagnose/builtin-rules/llm-response-truncated-no-continue.js +44 -0
  26. package/dist/trace-core/diagnose/builtin-rules/llm-response-truncated-no-continue.yaml +15 -0
  27. package/dist/trace-core/diagnose/builtin-rules/register.d.ts +1 -0
  28. package/dist/trace-core/diagnose/builtin-rules/register.js +11 -0
  29. package/dist/trace-core/diagnose/builtin-rules/retrieval-empty-no-fallback.d.ts +2 -0
  30. package/dist/trace-core/diagnose/builtin-rules/retrieval-empty-no-fallback.js +29 -0
  31. package/dist/trace-core/diagnose/builtin-rules/retrieval-empty-no-fallback.yaml +15 -0
  32. package/dist/trace-core/diagnose/builtin-rules/tool-error-swallowed.d.ts +2 -0
  33. package/dist/trace-core/diagnose/builtin-rules/tool-error-swallowed.js +45 -0
  34. package/dist/trace-core/diagnose/builtin-rules/tool-error-swallowed.yaml +15 -0
  35. package/dist/trace-core/diagnose/builtin-rules/tool-loop-no-state-change.d.ts +2 -0
  36. package/dist/trace-core/diagnose/builtin-rules/tool-loop-no-state-change.js +38 -0
  37. package/dist/trace-core/diagnose/builtin-rules/tool-loop-no-state-change.yaml +16 -0
  38. package/dist/trace-core/diagnose/index.d.ts +9 -0
  39. package/dist/trace-core/diagnose/index.js +104 -0
  40. package/dist/trace-core/diagnose/predicate-registry.d.ts +7 -0
  41. package/dist/trace-core/diagnose/predicate-registry.js +30 -0
  42. package/dist/trace-core/diagnose/report-assembler.d.ts +12 -0
  43. package/dist/trace-core/diagnose/report-assembler.js +90 -0
  44. package/dist/trace-core/diagnose/rule-loader.d.ts +11 -0
  45. package/dist/trace-core/diagnose/rule-loader.js +86 -0
  46. package/dist/trace-core/diagnose/schemas.d.ts +109 -0
  47. package/dist/trace-core/diagnose/schemas.js +94 -0
  48. package/dist/trace-core/diagnose/signal-probe.d.ts +5 -0
  49. package/dist/trace-core/diagnose/signal-probe.js +21 -0
  50. package/dist/trace-core/diagnose/synthesizer-template.d.ts +2 -0
  51. package/dist/trace-core/diagnose/synthesizer-template.js +49 -0
  52. package/dist/trace-core/diagnose/trace-shaper.d.ts +3 -0
  53. package/dist/trace-core/diagnose/trace-shaper.js +72 -0
  54. package/dist/trace-core/diagnose/types.d.ts +124 -0
  55. package/dist/trace-core/diagnose/types.js +1 -0
  56. package/package.json +14 -4
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ const TaxonomySchema = z.object({
3
+ signals_axis: z.enum(["interaction", "execution", "environment"]),
4
+ ms_class: z.enum([
5
+ "retry_loop",
6
+ "tool_misuse",
7
+ "context_loss",
8
+ "goal_drift",
9
+ "cascading_error",
10
+ "silent_quality_degradation",
11
+ ]),
12
+ });
13
+ const SuggestedFixSchema = z.object({
14
+ target: z.string().min(1),
15
+ change_template: z.string().min(1),
16
+ });
17
+ const VerifyWithSchema = z.object({
18
+ assertion_templates: z.array(z.string()).default([]),
19
+ });
20
+ // PR-A: only `predicate` branch (rubric XOR enforced in PR-B).
21
+ // We still encode the XOR shape so PR-B can enable rubric without breaking parsers.
22
+ export const RuleSchema = z
23
+ .object({
24
+ schema_version: z.literal("diagnosis-rule/v1"),
25
+ id: z.string().regex(/^[a-z][a-z0-9_]*$/),
26
+ severity: z.enum(["low", "medium", "high"]),
27
+ symptom: z.string().min(1),
28
+ taxonomy: TaxonomySchema,
29
+ suggested_fix: SuggestedFixSchema,
30
+ verify_with: VerifyWithSchema,
31
+ predicate: z.string().regex(/^builtin:[a-z][a-z0-9_]*$/).optional(),
32
+ rubric: z.unknown().optional(), // PR-B will define a real schema
33
+ params: z.record(z.string(), z.unknown()).default({}),
34
+ })
35
+ .refine((r) => Boolean(r.predicate) !== Boolean(r.rubric), { message: "exactly one of `predicate` or `rubric` must be present" });
36
+ const FindingSchema = z.object({
37
+ rule_id: z.string(),
38
+ judgment_kind: z.enum(["symbolic"]), // PR-B will add "rubric"
39
+ severity: z.enum(["low", "medium", "high"]),
40
+ symptom: z.string(),
41
+ likely_cause: z.string(),
42
+ evidence: z.object({
43
+ spans: z.array(z.string()),
44
+ excerpt: z.string(),
45
+ }),
46
+ suggested_fix: z.object({
47
+ target: z.string(),
48
+ change: z.string(),
49
+ }),
50
+ confidence: z.literal("low"),
51
+ verify_with: z.object({
52
+ suggested_eval_case: z.object({
53
+ query_id: z.string().nullable(),
54
+ query: z.string().nullable(),
55
+ assertions: z.array(z.string()),
56
+ }),
57
+ }),
58
+ });
59
+ const SummarySchema = z.object({
60
+ headline: z.string().max(160),
61
+ primary_root_cause: z
62
+ .object({
63
+ finding_ids: z.array(z.number().int().nonnegative()).min(1),
64
+ description: z.string(),
65
+ target_for_fix: z.string(),
66
+ })
67
+ .nullable(),
68
+ fix_priority: z.array(z.object({
69
+ finding_id: z.number().int().nonnegative(),
70
+ reason: z.string(),
71
+ })),
72
+ cross_finding_links: z.array(z.object({
73
+ finding_ids: z.array(z.number().int().nonnegative()).min(2),
74
+ relation: z.string(),
75
+ })),
76
+ });
77
+ export const ReportSchema = z.object({
78
+ schema_version: z.literal("trace-diagnose-report/v1"),
79
+ trace: z.object({
80
+ trace_id: z.string(),
81
+ agent_id: z.string().nullable(),
82
+ tenant: z.string().nullable(),
83
+ }),
84
+ run: z.object({
85
+ diagnosed_at: z.string(),
86
+ cli_version: z.string(),
87
+ mode: z.enum(["symbolic-only", "rubric-only", "hybrid"]),
88
+ rules_applied: z.array(z.string()),
89
+ rules_skipped: z.array(z.object({ rule_id: z.string(), reason: z.string() })),
90
+ synthesizer_mode: z.enum(["template", "agent"]),
91
+ }),
92
+ summary: SummarySchema,
93
+ findings: z.array(FindingSchema),
94
+ });
@@ -0,0 +1,5 @@
1
+ import type { Hit, Rule, TraceTree } from "./types.js";
2
+ export declare class RuleProbeError extends Error {
3
+ constructor(ruleId: string, cause: Error);
4
+ }
5
+ export declare function runRules(rules: Rule[], tree: TraceTree): Promise<Map<string, Hit[]>>;
@@ -0,0 +1,21 @@
1
+ import { resolvePredicate } from "./predicate-registry.js";
2
+ export class RuleProbeError extends Error {
3
+ constructor(ruleId, cause) {
4
+ super(`predicate failed for rule '${ruleId}': ${cause.message}`);
5
+ this.name = "RuleProbeError";
6
+ }
7
+ }
8
+ export async function runRules(rules, tree) {
9
+ const out = new Map();
10
+ for (const rule of rules) {
11
+ const fn = resolvePredicate(rule.predicateRef);
12
+ try {
13
+ const hits = fn(tree, rule.params);
14
+ out.set(rule.id, hits);
15
+ }
16
+ catch (e) {
17
+ throw new RuleProbeError(rule.id, e);
18
+ }
19
+ }
20
+ return out;
21
+ }
@@ -0,0 +1,2 @@
1
+ import type { Finding, Summary } from "./types.js";
2
+ export declare function templateSynthesize(findings: Finding[]): Summary;
@@ -0,0 +1,49 @@
1
+ const SEVERITY_RANK = { high: 3, medium: 2, low: 1 };
2
+ function overlapRatio(a, b) {
3
+ if (a.length === 0 || b.length === 0)
4
+ return 0;
5
+ const setA = new Set(a);
6
+ const intersect = b.filter((x) => setA.has(x)).length;
7
+ const smaller = Math.min(a.length, b.length);
8
+ return intersect / smaller;
9
+ }
10
+ export function templateSynthesize(findings) {
11
+ if (findings.length === 0) {
12
+ return {
13
+ headline: "No findings",
14
+ primaryRootCause: null,
15
+ fixPriority: [],
16
+ crossFindingLinks: [],
17
+ };
18
+ }
19
+ // Sort indices by severity desc, stable on original index (so same input → same output).
20
+ const indices = findings.map((_, i) => i);
21
+ indices.sort((i, j) => {
22
+ const r = SEVERITY_RANK[findings[j].severity] - SEVERITY_RANK[findings[i].severity];
23
+ return r !== 0 ? r : i - j;
24
+ });
25
+ const topIdx = indices[0];
26
+ const top = findings[topIdx];
27
+ const headline = `see findings[${topIdx}]: ${top.symptom}`;
28
+ const primaryRootCause = {
29
+ findingIds: [topIdx],
30
+ description: `Top-severity finding from rule '${top.ruleId}': ${top.symptom}`,
31
+ targetForFix: top.suggestedFix.target,
32
+ };
33
+ const fixPriority = indices.map((i) => ({
34
+ findingId: i,
35
+ reason: `severity=${findings[i].severity}`,
36
+ }));
37
+ const crossFindingLinks = [];
38
+ for (let i = 0; i < findings.length; i++) {
39
+ for (let j = i + 1; j < findings.length; j++) {
40
+ if (overlapRatio(findings[i].evidence.spans, findings[j].evidence.spans) >= 0.5) {
41
+ crossFindingLinks.push({
42
+ findingIds: [i, j],
43
+ relation: "overlapping_evidence_spans",
44
+ });
45
+ }
46
+ }
47
+ }
48
+ return { headline, primaryRootCause, fixPriority, crossFindingLinks };
49
+ }
@@ -0,0 +1,3 @@
1
+ import type { TraceTree } from "./types.js";
2
+ import type { RawSpan } from "../../api/trace.js";
3
+ export declare function assembleTraceTree(traceId: string, raw: RawSpan[]): TraceTree;
@@ -0,0 +1,72 @@
1
+ // Map from OTel GenAI `gen_ai.operation.name` (the cross-runtime standard) to
2
+ // the diagnostic SpanKind buckets rules filter on. `agent.trace.type` is kept
3
+ // as a fallback for runtimes/fixtures that pre-tag spans with our own taxonomy.
4
+ const KIND_MAP = {
5
+ // OTel GenAI semconv operation names
6
+ chat: "llm",
7
+ text_completion: "llm",
8
+ embeddings: "retrieval",
9
+ execute_tool: "tool",
10
+ // pre-existing custom taxonomy (synthetic fixtures, optional runtime tag)
11
+ model: "llm",
12
+ llm: "llm",
13
+ tool: "tool",
14
+ retrieval: "retrieval",
15
+ reasoning: "reasoning",
16
+ };
17
+ function deriveKind(attrs) {
18
+ const op = attrs["gen_ai.operation.name"];
19
+ if (typeof op === "string" && op in KIND_MAP)
20
+ return KIND_MAP[op];
21
+ const t = attrs["agent.trace.type"];
22
+ if (typeof t === "string" && t in KIND_MAP)
23
+ return KIND_MAP[t];
24
+ return "unknown";
25
+ }
26
+ function deriveStatus(raw) {
27
+ const code = raw?.code?.toUpperCase();
28
+ if (code === "OK")
29
+ return "ok";
30
+ if (code === "ERROR")
31
+ return "error";
32
+ return "unset";
33
+ }
34
+ function durationMs(start, end) {
35
+ if (!start || !end)
36
+ return 0;
37
+ // string nanos → BigInt to avoid precision loss, then convert to ms.
38
+ const s = BigInt(start);
39
+ const e = BigInt(end);
40
+ return Number((e - s) / 1000000n);
41
+ }
42
+ export function assembleTraceTree(traceId, raw) {
43
+ const spans = raw.map((r) => {
44
+ const attrs = r.attributes ?? {};
45
+ return {
46
+ spanId: r.spanId,
47
+ parentSpanId: r.parentSpanId ?? null,
48
+ name: r.name ?? "",
49
+ kind: deriveKind(attrs),
50
+ startTimeUnixNano: r.startTimeUnixNano ?? "0",
51
+ endTimeUnixNano: r.endTimeUnixNano ?? "0",
52
+ durationMs: durationMs(r.startTimeUnixNano, r.endTimeUnixNano),
53
+ status: deriveStatus(r.status),
54
+ attributes: attrs,
55
+ };
56
+ });
57
+ const byId = new Map();
58
+ const parentToChildren = new Map();
59
+ const byKind = new Map();
60
+ for (const s of spans) {
61
+ byId.set(s.spanId, s);
62
+ const arr = parentToChildren.get(s.parentSpanId) ?? [];
63
+ arr.push(s);
64
+ parentToChildren.set(s.parentSpanId, arr);
65
+ const kindArr = byKind.get(s.kind) ?? [];
66
+ kindArr.push(s);
67
+ byKind.set(s.kind, kindArr);
68
+ }
69
+ const roots = parentToChildren.get(null) ?? [];
70
+ const root = roots.length > 0 ? roots[0] : null;
71
+ return { traceId, spans, byId, parentToChildren, byKind, root };
72
+ }
@@ -0,0 +1,124 @@
1
+ export interface SpanAttributes {
2
+ [key: string]: unknown;
3
+ }
4
+ export interface Span {
5
+ spanId: string;
6
+ parentSpanId: string | null;
7
+ name: string;
8
+ kind: SpanKind;
9
+ startTimeUnixNano: string;
10
+ endTimeUnixNano: string;
11
+ durationMs: number;
12
+ status: 'ok' | 'error' | 'unset';
13
+ attributes: SpanAttributes;
14
+ }
15
+ export type SpanKind = 'tool' | 'llm' | 'retrieval' | 'reasoning' | 'unknown';
16
+ export interface TraceTree {
17
+ traceId: string;
18
+ spans: Span[];
19
+ byId: Map<string, Span>;
20
+ parentToChildren: Map<string | null, Span[]>;
21
+ byKind: Map<SpanKind, Span[]>;
22
+ root: Span | null;
23
+ }
24
+ export interface RuleTaxonomy {
25
+ signalsAxis: 'interaction' | 'execution' | 'environment';
26
+ msClass: 'retry_loop' | 'tool_misuse' | 'context_loss' | 'goal_drift' | 'cascading_error' | 'silent_quality_degradation';
27
+ }
28
+ export interface Rule {
29
+ schemaVersion: 'diagnosis-rule/v1';
30
+ id: string;
31
+ severity: 'low' | 'medium' | 'high';
32
+ symptom: string;
33
+ taxonomy: RuleTaxonomy;
34
+ suggestedFix: {
35
+ target: string;
36
+ changeTemplate: string;
37
+ };
38
+ verifyWith: {
39
+ assertionTemplates: string[];
40
+ };
41
+ predicateRef: string;
42
+ params: Record<string, unknown>;
43
+ sourcePath: string;
44
+ }
45
+ export interface Hit {
46
+ evidenceSpans: string[];
47
+ excerpt: string;
48
+ bindings: Record<string, unknown>;
49
+ }
50
+ export type Predicate = (trace: TraceTree, params: Record<string, unknown>) => Hit[];
51
+ export interface Finding {
52
+ ruleId: string;
53
+ judgmentKind: 'symbolic';
54
+ severity: 'low' | 'medium' | 'high';
55
+ symptom: string;
56
+ likelyCause: string;
57
+ evidence: {
58
+ spans: string[];
59
+ excerpt: string;
60
+ };
61
+ suggestedFix: {
62
+ target: string;
63
+ change: string;
64
+ };
65
+ confidence: 'low';
66
+ verifyWith: {
67
+ suggestedEvalCase: {
68
+ queryId: string | null;
69
+ query: string | null;
70
+ assertions: string[];
71
+ };
72
+ };
73
+ }
74
+ export interface SummaryRootCause {
75
+ findingIds: number[];
76
+ description: string;
77
+ targetForFix: string;
78
+ }
79
+ export interface SummaryFixPriority {
80
+ findingId: number;
81
+ reason: string;
82
+ }
83
+ export interface SummaryCrossLink {
84
+ findingIds: number[];
85
+ relation: string;
86
+ }
87
+ export interface Summary {
88
+ headline: string;
89
+ primaryRootCause: SummaryRootCause | null;
90
+ fixPriority: SummaryFixPriority[];
91
+ crossFindingLinks: SummaryCrossLink[];
92
+ }
93
+ export interface Report {
94
+ schemaVersion: 'trace-diagnose-report/v1';
95
+ trace: {
96
+ traceId: string;
97
+ agentId: string | null;
98
+ tenant: string | null;
99
+ };
100
+ run: {
101
+ diagnosedAt: string;
102
+ cliVersion: string;
103
+ mode: 'symbolic-only';
104
+ rulesApplied: string[];
105
+ rulesSkipped: {
106
+ ruleId: string;
107
+ reason: string;
108
+ }[];
109
+ synthesizerMode: 'template';
110
+ };
111
+ summary: Summary;
112
+ findings: Finding[];
113
+ }
114
+ export interface DiagnoseOpts {
115
+ out: string | null;
116
+ rulesDir: string | null;
117
+ noBuiltin: boolean;
118
+ noLlm: true;
119
+ agentProvider: string | null;
120
+ timeoutMs: number;
121
+ baseUrl: string;
122
+ token: string;
123
+ businessDomain: string;
124
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kweaver-ai/kweaver-sdk",
3
- "version": "0.7.4",
3
+ "version": "0.8.1",
4
4
  "description": "KWeaver TypeScript SDK — CLI tool and programmatic API for knowledge networks and Decision Agents.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -24,12 +24,17 @@
24
24
  ],
25
25
  "scripts": {
26
26
  "dev": "tsx watch src/cli.ts",
27
- "build": "node node_modules/typescript/bin/tsc -p tsconfig.json && rm -rf dist/templates && cp -R src/templates dist/templates",
27
+ "build": "node node_modules/typescript/bin/tsc -p tsconfig.json && rm -rf dist/templates && cp -R src/templates dist/templates && cp src/trace-core/diagnose/builtin-rules/*.yaml dist/trace-core/diagnose/builtin-rules/",
28
28
  "start": "node ./dist/cli.js",
29
29
  "lint": "node node_modules/typescript/bin/tsc --noEmit -p tsconfig.json",
30
30
  "test": "node --import tsx --test test/*.test.ts",
31
31
  "test:e2e": "node --import tsx --test test/e2e/*.test.ts",
32
- "prepublishOnly": "npm run build"
32
+ "prepublishOnly": "npm run build",
33
+ "docs": "node scripts/build-docs.mjs",
34
+ "docs:zh": "node scripts/build-docs.mjs --zh",
35
+ "docs:all": "npm run docs && npm run docs:zh",
36
+ "docs:serve": "npm run docs && serve ../../docs/reference/typescript-api-html -p 8766 -n",
37
+ "docs:serve:zh": "npm run docs:zh && serve ../../docs/reference/typescript-api-html-zh -p 8767 -n"
33
38
  },
34
39
  "keywords": [
35
40
  "cli",
@@ -48,10 +53,13 @@
48
53
  "node": ">=22"
49
54
  },
50
55
  "devDependencies": {
56
+ "@types/js-yaml": "^4.0.9",
51
57
  "@types/node": "^24.6.0",
52
58
  "@types/react": "^19.2.14",
53
59
  "@types/yargs": "^17.0.35",
60
+ "serve": "^14.2.5",
54
61
  "tsx": "^4.20.5",
62
+ "typedoc": "^0.28.19",
55
63
  "typescript": "^5.9.3"
56
64
  },
57
65
  "dependencies": {
@@ -63,10 +71,12 @@
63
71
  "ink": "^6.8.0",
64
72
  "ink-spinner": "^5.0.0",
65
73
  "ink-text-input": "^6.0.0",
74
+ "js-yaml": "^4.1.1",
66
75
  "jszip": "^3.10.1",
67
76
  "marked": "^11.2.0",
68
77
  "react": "^19.2.4",
69
78
  "string-width": "^8.2.0",
70
- "yargs": "^18.0.0"
79
+ "yargs": "^18.0.0",
80
+ "zod": "^4.4.3"
71
81
  }
72
82
  }