@kb-labs/adapters 0.5.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/.cursorrules +32 -0
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/deploy.yml +28 -0
- package/.github/workflows/docker-build.yml +25 -0
- package/.github/workflows/drift-check.yml +10 -0
- package/.github/workflows/profiles-validate.yml +16 -0
- package/.github/workflows/release.yml +8 -0
- package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
- package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
- package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
- package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
- package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
- package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
- package/.kb/devkit/agents/release-manager/context.globs +7 -0
- package/.kb/devkit/agents/release-manager/prompt.md +27 -0
- package/.kb/devkit/agents/release-manager/runbook.md +17 -0
- package/.kb/devkit/agents/test-generator/context.globs +7 -0
- package/.kb/devkit/agents/test-generator/prompt.md +27 -0
- package/.kb/devkit/agents/test-generator/runbook.md +18 -0
- package/CONTRIBUTING.md +90 -0
- package/IMPLEMENTATION_COMPLETE.md +416 -0
- package/LICENSE +186 -0
- package/README-TEMPLATE.md +179 -0
- package/README.md +306 -0
- package/docs/DOCUMENTATION.md +74 -0
- package/docs/adr/0000-template.md +49 -0
- package/docs/adr/0001-architecture-and-repository-layout.md +33 -0
- package/docs/adr/0002-plugins-and-extensibility.md +46 -0
- package/docs/adr/0003-package-and-module-boundaries.md +37 -0
- package/docs/adr/0004-versioning-and-release-policy.md +38 -0
- package/docs/adr/0005-use-devkit-for-shared-tooling.md +48 -0
- package/docs/adr/0006-adopt-devkit-sync.md +47 -0
- package/docs/adr/0007-drift-kit-check.md +72 -0
- package/docs/adr/0008-devkit-sync-wrapper-strategy.md +67 -0
- package/docs/naming-convention.md +272 -0
- package/eslint.config.js +27 -0
- package/kb-labs.config.json +5 -0
- package/package.json +84 -0
- package/package.json.bin +25 -0
- package/package.json.lib +30 -0
- package/packages/adapters-analytics-duckdb/package.json +54 -0
- package/packages/adapters-analytics-duckdb/scripts/migrate-from-jsonl.mjs +253 -0
- package/packages/adapters-analytics-duckdb/src/index.ts +380 -0
- package/packages/adapters-analytics-duckdb/src/manifest.ts +36 -0
- package/packages/adapters-analytics-duckdb/src/schema.ts +161 -0
- package/packages/adapters-analytics-duckdb/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-duckdb/tsconfig.json +9 -0
- package/packages/adapters-analytics-duckdb/tsup.config.ts +9 -0
- package/packages/adapters-analytics-file/README.md +32 -0
- package/packages/adapters-analytics-file/eslint.config.js +27 -0
- package/packages/adapters-analytics-file/package.json +50 -0
- package/packages/adapters-analytics-file/src/__tests__/daily-stats.spec.ts +287 -0
- package/packages/adapters-analytics-file/src/__tests__/scoped-analytics.test.ts +233 -0
- package/packages/adapters-analytics-file/src/index.test.ts +214 -0
- package/packages/adapters-analytics-file/src/index.ts +830 -0
- package/packages/adapters-analytics-file/src/manifest.ts +45 -0
- package/packages/adapters-analytics-file/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-file/tsconfig.json +9 -0
- package/packages/adapters-analytics-file/tsup.config.ts +9 -0
- package/packages/adapters-analytics-sqlite/package.json +55 -0
- package/packages/adapters-analytics-sqlite/scripts/migrate-from-jsonl.mjs +194 -0
- package/packages/adapters-analytics-sqlite/src/index.ts +460 -0
- package/packages/adapters-analytics-sqlite/src/manifest.ts +41 -0
- package/packages/adapters-analytics-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-analytics-sqlite/tsconfig.json +9 -0
- package/packages/adapters-analytics-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-environment-docker/README.md +28 -0
- package/packages/adapters-environment-docker/eslint.config.js +5 -0
- package/packages/adapters-environment-docker/package.json +49 -0
- package/packages/adapters-environment-docker/src/index.test.ts +138 -0
- package/packages/adapters-environment-docker/src/index.ts +439 -0
- package/packages/adapters-environment-docker/src/manifest.ts +65 -0
- package/packages/adapters-environment-docker/tsconfig.build.json +15 -0
- package/packages/adapters-environment-docker/tsconfig.json +16 -0
- package/packages/adapters-environment-docker/tsup.config.ts +9 -0
- package/packages/adapters-eventbus-cache/README.md +242 -0
- package/packages/adapters-eventbus-cache/eslint.config.js +27 -0
- package/packages/adapters-eventbus-cache/package.json +46 -0
- package/packages/adapters-eventbus-cache/src/index.test.ts +235 -0
- package/packages/adapters-eventbus-cache/src/index.ts +215 -0
- package/packages/adapters-eventbus-cache/src/manifest.ts +50 -0
- package/packages/adapters-eventbus-cache/src/types.ts +58 -0
- package/packages/adapters-eventbus-cache/tsconfig.build.json +15 -0
- package/packages/adapters-eventbus-cache/tsconfig.json +9 -0
- package/packages/adapters-eventbus-cache/tsup.config.ts +9 -0
- package/packages/adapters-fs/README.md +171 -0
- package/packages/adapters-fs/allowed.txt +1 -0
- package/packages/adapters-fs/conflict.txt +1 -0
- package/packages/adapters-fs/dest.txt +1 -0
- package/packages/adapters-fs/eslint.config.js +27 -0
- package/packages/adapters-fs/exists.txt +1 -0
- package/packages/adapters-fs/not-allowed.txt +1 -0
- package/packages/adapters-fs/other.txt +1 -0
- package/packages/adapters-fs/package.json +55 -0
- package/packages/adapters-fs/public/file1.txt +1 -0
- package/packages/adapters-fs/public/file2.txt +1 -0
- package/packages/adapters-fs/secret.txt +1 -0
- package/packages/adapters-fs/secrets/key.txt +1 -0
- package/packages/adapters-fs/src/index.test.ts +243 -0
- package/packages/adapters-fs/src/index.ts +258 -0
- package/packages/adapters-fs/src/manifest.ts +35 -0
- package/packages/adapters-fs/src/secure-storage.test.ts +380 -0
- package/packages/adapters-fs/src/secure-storage.ts +268 -0
- package/packages/adapters-fs/test.json +1 -0
- package/packages/adapters-fs/test.txt +1 -0
- package/packages/adapters-fs/test.xyz +1 -0
- package/packages/adapters-fs/test1.txt +1 -0
- package/packages/adapters-fs/test2.txt +1 -0
- package/packages/adapters-fs/tsconfig.build.json +15 -0
- package/packages/adapters-fs/tsconfig.json +9 -0
- package/packages/adapters-fs/tsup.config.ts +8 -0
- package/packages/adapters-fs/vitest.config.ts +19 -0
- package/packages/adapters-log-ringbuffer/README.md +228 -0
- package/packages/adapters-log-ringbuffer/eslint.config.js +27 -0
- package/packages/adapters-log-ringbuffer/package.json +47 -0
- package/packages/adapters-log-ringbuffer/src/__tests__/ring-buffer.test.ts +450 -0
- package/packages/adapters-log-ringbuffer/src/index.ts +212 -0
- package/packages/adapters-log-ringbuffer/src/manifest.ts +30 -0
- package/packages/adapters-log-ringbuffer/tsconfig.build.json +15 -0
- package/packages/adapters-log-ringbuffer/tsconfig.json +9 -0
- package/packages/adapters-log-ringbuffer/tsup.config.ts +9 -0
- package/packages/adapters-log-ringbuffer/vitest.config.ts +14 -0
- package/packages/adapters-log-sqlite/README.md +396 -0
- package/packages/adapters-log-sqlite/eslint.config.js +27 -0
- package/packages/adapters-log-sqlite/package.json +49 -0
- package/packages/adapters-log-sqlite/src/__tests__/log-persistence.test.ts +718 -0
- package/packages/adapters-log-sqlite/src/index.ts +1068 -0
- package/packages/adapters-log-sqlite/src/manifest.ts +36 -0
- package/packages/adapters-log-sqlite/src/schema.sql +46 -0
- package/packages/adapters-log-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-log-sqlite/tsconfig.json +9 -0
- package/packages/adapters-log-sqlite/tsup.config.ts +9 -0
- package/packages/adapters-log-sqlite/vitest.config.ts +15 -0
- package/packages/adapters-mongodb/README.md +147 -0
- package/packages/adapters-mongodb/eslint.config.js +27 -0
- package/packages/adapters-mongodb/package.json +53 -0
- package/packages/adapters-mongodb/src/index.ts +428 -0
- package/packages/adapters-mongodb/src/manifest.ts +45 -0
- package/packages/adapters-mongodb/src/secure-document.ts +231 -0
- package/packages/adapters-mongodb/tsconfig.build.json +15 -0
- package/packages/adapters-mongodb/tsconfig.json +9 -0
- package/packages/adapters-mongodb/tsup.config.ts +8 -0
- package/packages/adapters-openai/README.md +151 -0
- package/packages/adapters-openai/embeddings.ts +37 -0
- package/packages/adapters-openai/eslint.config.js +26 -0
- package/packages/adapters-openai/index.ts +22 -0
- package/packages/adapters-openai/package.json +57 -0
- package/packages/adapters-openai/src/embeddings-manifest.ts +45 -0
- package/packages/adapters-openai/src/embeddings.ts +104 -0
- package/packages/adapters-openai/src/index.ts +13 -0
- package/packages/adapters-openai/src/llm.ts +304 -0
- package/packages/adapters-openai/src/manifest.ts +47 -0
- package/packages/adapters-openai/tsconfig.build.json +15 -0
- package/packages/adapters-openai/tsconfig.json +9 -0
- package/packages/adapters-openai/tsup.config.ts +8 -0
- package/packages/adapters-pino/README.md +152 -0
- package/packages/adapters-pino/eslint.config.js +27 -0
- package/packages/adapters-pino/package.json +49 -0
- package/packages/adapters-pino/src/index.test.ts +44 -0
- package/packages/adapters-pino/src/index.ts +322 -0
- package/packages/adapters-pino/src/log-ring-buffer.ts +142 -0
- package/packages/adapters-pino/src/manifest.ts +49 -0
- package/packages/adapters-pino/tsconfig.build.json +15 -0
- package/packages/adapters-pino/tsconfig.json +9 -0
- package/packages/adapters-pino/tsup.config.ts +9 -0
- package/packages/adapters-pino-http/README.md +141 -0
- package/packages/adapters-pino-http/eslint.config.js +27 -0
- package/packages/adapters-pino-http/package.json +46 -0
- package/packages/adapters-pino-http/src/index.ts +229 -0
- package/packages/adapters-pino-http/tsconfig.build.json +15 -0
- package/packages/adapters-pino-http/tsconfig.json +9 -0
- package/packages/adapters-pino-http/tsup.config.ts +9 -0
- package/packages/adapters-qdrant/README.md +166 -0
- package/packages/adapters-qdrant/eslint.config.js +27 -0
- package/packages/adapters-qdrant/package.json +49 -0
- package/packages/adapters-qdrant/src/index.ts +490 -0
- package/packages/adapters-qdrant/src/manifest.ts +54 -0
- package/packages/adapters-qdrant/src/retry.ts +204 -0
- package/packages/adapters-qdrant/tsconfig.build.json +15 -0
- package/packages/adapters-qdrant/tsconfig.json +9 -0
- package/packages/adapters-qdrant/tsup.config.ts +9 -0
- package/packages/adapters-redis/README.md +159 -0
- package/packages/adapters-redis/eslint.config.js +27 -0
- package/packages/adapters-redis/package.json +49 -0
- package/packages/adapters-redis/src/index.ts +164 -0
- package/packages/adapters-redis/src/manifest.ts +49 -0
- package/packages/adapters-redis/tsconfig.build.json +15 -0
- package/packages/adapters-redis/tsconfig.json +9 -0
- package/packages/adapters-redis/tsup.config.ts +9 -0
- package/packages/adapters-snapshot-localfs/README.md +10 -0
- package/packages/adapters-snapshot-localfs/eslint.config.js +2 -0
- package/packages/adapters-snapshot-localfs/package.json +46 -0
- package/packages/adapters-snapshot-localfs/src/index.test.ts +40 -0
- package/packages/adapters-snapshot-localfs/src/index.ts +292 -0
- package/packages/adapters-snapshot-localfs/src/manifest.ts +32 -0
- package/packages/adapters-snapshot-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-snapshot-localfs/tsconfig.json +16 -0
- package/packages/adapters-snapshot-localfs/tsup.config.ts +11 -0
- package/packages/adapters-sqlite/README.md +163 -0
- package/packages/adapters-sqlite/eslint.config.js +27 -0
- package/packages/adapters-sqlite/package.json +54 -0
- package/packages/adapters-sqlite/src/index.test.ts +245 -0
- package/packages/adapters-sqlite/src/index.ts +382 -0
- package/packages/adapters-sqlite/src/manifest.ts +47 -0
- package/packages/adapters-sqlite/src/secure-sql.test.ts +290 -0
- package/packages/adapters-sqlite/src/secure-sql.ts +281 -0
- package/packages/adapters-sqlite/tsconfig.build.json +15 -0
- package/packages/adapters-sqlite/tsconfig.json +9 -0
- package/packages/adapters-sqlite/tsup.config.ts +8 -0
- package/packages/adapters-sqlite/vitest.config.ts +19 -0
- package/packages/adapters-transport/README.md +170 -0
- package/packages/adapters-transport/eslint.config.js +27 -0
- package/packages/adapters-transport/package.json +49 -0
- package/packages/adapters-transport/src/__tests__/unix-socket-server.test.ts +550 -0
- package/packages/adapters-transport/src/index.ts +101 -0
- package/packages/adapters-transport/src/ipc-transport.ts +228 -0
- package/packages/adapters-transport/src/transport.ts +224 -0
- package/packages/adapters-transport/src/types.ts +92 -0
- package/packages/adapters-transport/src/unix-socket-server.ts +193 -0
- package/packages/adapters-transport/src/unix-socket-transport.ts +280 -0
- package/packages/adapters-transport/tsconfig.build.json +15 -0
- package/packages/adapters-transport/tsconfig.json +9 -0
- package/packages/adapters-transport/tsup.config.ts +9 -0
- package/packages/adapters-vibeproxy/README.md +159 -0
- package/packages/adapters-vibeproxy/eslint.config.js +27 -0
- package/packages/adapters-vibeproxy/package.json +51 -0
- package/packages/adapters-vibeproxy/src/index.ts +13 -0
- package/packages/adapters-vibeproxy/src/llm.ts +437 -0
- package/packages/adapters-vibeproxy/src/manifest.ts +51 -0
- package/packages/adapters-vibeproxy/tsconfig.build.json +15 -0
- package/packages/adapters-vibeproxy/tsconfig.json +9 -0
- package/packages/adapters-vibeproxy/tsup.config.ts +8 -0
- package/packages/adapters-workspace-agent/package.json +46 -0
- package/packages/adapters-workspace-agent/src/__tests__/adapter.test.ts +212 -0
- package/packages/adapters-workspace-agent/src/index.ts +220 -0
- package/packages/adapters-workspace-agent/src/manifest.ts +36 -0
- package/packages/adapters-workspace-agent/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-agent/tsconfig.json +16 -0
- package/packages/adapters-workspace-agent/tsup.config.ts +11 -0
- package/packages/adapters-workspace-localfs/README.md +9 -0
- package/packages/adapters-workspace-localfs/eslint.config.js +2 -0
- package/packages/adapters-workspace-localfs/package.json +46 -0
- package/packages/adapters-workspace-localfs/src/index.test.ts +27 -0
- package/packages/adapters-workspace-localfs/src/index.ts +172 -0
- package/packages/adapters-workspace-localfs/src/manifest.ts +32 -0
- package/packages/adapters-workspace-localfs/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-localfs/tsconfig.json +16 -0
- package/packages/adapters-workspace-localfs/tsup.config.ts +11 -0
- package/packages/adapters-workspace-worktree/README.md +9 -0
- package/packages/adapters-workspace-worktree/eslint.config.js +2 -0
- package/packages/adapters-workspace-worktree/package.json +46 -0
- package/packages/adapters-workspace-worktree/src/index.test.ts +38 -0
- package/packages/adapters-workspace-worktree/src/index.ts +245 -0
- package/packages/adapters-workspace-worktree/src/manifest.ts +38 -0
- package/packages/adapters-workspace-worktree/tsconfig.build.json +15 -0
- package/packages/adapters-workspace-worktree/tsconfig.json +16 -0
- package/packages/adapters-workspace-worktree/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +2800 -0
- package/prettierrc.json +1 -0
- package/scripts/devkit-sync.mjs +37 -0
- package/scripts/hooks/post-push +9 -0
- package/scripts/hooks/pre-commit +9 -0
- package/scripts/hooks/pre-push +9 -0
- package/test-integration.ts +242 -0
- package/test.txt +1 -0
- package/tsconfig.base.json +6 -0
- package/tsconfig.build.json +15 -0
- package/tsconfig.json +9 -0
- package/tsconfig.paths.json +26 -0
- package/tsconfig.tools.json +17 -0
- package/tsup.config.bin.ts +34 -0
- package/tsup.config.cli.ts +41 -0
- package/tsup.config.dual.ts +46 -0
- package/tsup.config.ts +36 -0
- package/tsup.external.json +103 -0
- package/vitest.config.ts +2 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-openai/llm
|
|
3
|
+
* OpenAI implementation of ILLM interface.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import OpenAI from "openai";
|
|
7
|
+
import type {
|
|
8
|
+
ILLM,
|
|
9
|
+
LLMOptions,
|
|
10
|
+
LLMResponse,
|
|
11
|
+
LLMMessage,
|
|
12
|
+
LLMToolCallOptions,
|
|
13
|
+
LLMToolCallResponse,
|
|
14
|
+
LLMTool,
|
|
15
|
+
LLMToolCall,
|
|
16
|
+
LLMProtocolCapabilities,
|
|
17
|
+
} from "@kb-labs/core-platform";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Configuration for OpenAI LLM adapter.
|
|
21
|
+
*/
|
|
22
|
+
export interface OpenAILLMConfig {
|
|
23
|
+
/** OpenAI API key (defaults to OPENAI_API_KEY env var) */
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
/** Base URL for API (optional, for proxies or Azure) */
|
|
26
|
+
baseURL?: string;
|
|
27
|
+
/** Default model to use */
|
|
28
|
+
defaultModel?: string;
|
|
29
|
+
/** Organization ID (optional) */
|
|
30
|
+
organization?: string;
|
|
31
|
+
/** Default max output tokens when caller does not specify. Overrides the API default (4096). */
|
|
32
|
+
defaultMaxTokens?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Default max output tokens — avoids hitting the 4096 API default mid-response. */
|
|
36
|
+
const DEFAULT_MAX_TOKENS = 16_384;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* OpenAI implementation of ILLM interface.
|
|
40
|
+
*/
|
|
41
|
+
export class OpenAILLM implements ILLM {
|
|
42
|
+
private client: OpenAI;
|
|
43
|
+
private defaultModel: string;
|
|
44
|
+
private defaultMaxTokens: number;
|
|
45
|
+
|
|
46
|
+
constructor(config: OpenAILLMConfig = {}) {
|
|
47
|
+
this.client = new OpenAI({
|
|
48
|
+
apiKey: config.apiKey ?? process.env.OPENAI_API_KEY,
|
|
49
|
+
baseURL: config.baseURL,
|
|
50
|
+
organization: config.organization,
|
|
51
|
+
});
|
|
52
|
+
this.defaultModel = config.defaultModel ?? "gpt-4o-mini";
|
|
53
|
+
this.defaultMaxTokens = config.defaultMaxTokens ?? DEFAULT_MAX_TOKENS;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getProtocolCapabilities(): LLMProtocolCapabilities {
|
|
57
|
+
return {
|
|
58
|
+
cache: {
|
|
59
|
+
supported: true,
|
|
60
|
+
protocol: "auto_prefix",
|
|
61
|
+
scopes: ["prefix", "segments"],
|
|
62
|
+
},
|
|
63
|
+
stream: {
|
|
64
|
+
supported: true,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private buildCacheRequestPatch(options?: LLMOptions): Record<string, unknown> {
|
|
70
|
+
const cache = options?.execution?.cache;
|
|
71
|
+
if (!cache) {
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const patch: Record<string, unknown> = {
|
|
76
|
+
metadata: {
|
|
77
|
+
kb_cache_mode: cache.mode ?? "prefer",
|
|
78
|
+
kb_cache_scope: cache.scope ?? "prefix",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (typeof cache.ttlSec === "number") {
|
|
83
|
+
(patch.metadata as Record<string, unknown>).kb_cache_ttl_sec = String(
|
|
84
|
+
cache.ttlSec,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (cache.key) {
|
|
89
|
+
// Best-effort hint: supported by newer OpenAI prompt caching stacks.
|
|
90
|
+
patch.prompt_cache_key = cache.key;
|
|
91
|
+
(patch.metadata as Record<string, unknown>).kb_cache_key = cache.key;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return patch;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async complete(prompt: string, options?: LLMOptions): Promise<LLMResponse> {
|
|
98
|
+
const model = options?.model ?? this.defaultModel;
|
|
99
|
+
const messages: OpenAI.ChatCompletionMessageParam[] = [];
|
|
100
|
+
|
|
101
|
+
// Add system prompt if provided
|
|
102
|
+
if (options?.systemPrompt) {
|
|
103
|
+
messages.push({ role: "system", content: options.systemPrompt });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add user prompt
|
|
107
|
+
messages.push({ role: "user", content: prompt });
|
|
108
|
+
|
|
109
|
+
const response = await this.client.chat.completions.create({
|
|
110
|
+
model,
|
|
111
|
+
messages,
|
|
112
|
+
temperature: options?.temperature,
|
|
113
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
114
|
+
stop: options?.stop,
|
|
115
|
+
...(this.buildCacheRequestPatch(options) as Record<string, unknown>),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const choice = response.choices[0];
|
|
119
|
+
const content = choice?.message?.content ?? "";
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
content,
|
|
123
|
+
usage: {
|
|
124
|
+
promptTokens: response.usage?.prompt_tokens ?? 0,
|
|
125
|
+
completionTokens: response.usage?.completion_tokens ?? 0,
|
|
126
|
+
cacheReadTokens:
|
|
127
|
+
(response.usage as unknown as { prompt_tokens_details?: { cached_tokens?: number } })
|
|
128
|
+
?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
129
|
+
providerUsage: response.usage as unknown as Record<string, unknown>,
|
|
130
|
+
},
|
|
131
|
+
model: response.model,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async *stream(prompt: string, options?: LLMOptions): AsyncIterable<string> {
|
|
136
|
+
const model = options?.model ?? this.defaultModel;
|
|
137
|
+
const messages: OpenAI.ChatCompletionMessageParam[] = [];
|
|
138
|
+
|
|
139
|
+
// Add system prompt if provided
|
|
140
|
+
if (options?.systemPrompt) {
|
|
141
|
+
messages.push({ role: "system", content: options.systemPrompt });
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Add user prompt
|
|
145
|
+
messages.push({ role: "user", content: prompt });
|
|
146
|
+
|
|
147
|
+
const stream = await this.client.chat.completions.create({
|
|
148
|
+
model,
|
|
149
|
+
messages,
|
|
150
|
+
temperature: options?.temperature,
|
|
151
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
152
|
+
stop: options?.stop,
|
|
153
|
+
stream: true,
|
|
154
|
+
...(this.buildCacheRequestPatch(options) as Record<string, unknown>),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
for await (const chunk of stream) {
|
|
158
|
+
const content = chunk.choices[0]?.delta?.content;
|
|
159
|
+
if (content) {
|
|
160
|
+
yield content;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Chat with native tool calling support.
|
|
167
|
+
* Uses OpenAI's native function calling API.
|
|
168
|
+
*/
|
|
169
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- Complex due to OpenAI API format conversion (messages, tools, tool_choice)
|
|
170
|
+
async chatWithTools(
|
|
171
|
+
messages: LLMMessage[],
|
|
172
|
+
options: LLMToolCallOptions,
|
|
173
|
+
): Promise<LLMToolCallResponse> {
|
|
174
|
+
const model = options?.model ?? this.defaultModel;
|
|
175
|
+
|
|
176
|
+
// Convert LLMMessage[] to OpenAI format
|
|
177
|
+
const openaiMessages: OpenAI.ChatCompletionMessageParam[] = messages.map(
|
|
178
|
+
(msg) => {
|
|
179
|
+
if (msg.role === "tool") {
|
|
180
|
+
return {
|
|
181
|
+
role: "tool" as const,
|
|
182
|
+
content: msg.content,
|
|
183
|
+
tool_call_id: msg.toolCallId || "",
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (msg.role === "assistant" && msg.toolCalls && msg.toolCalls.length > 0) {
|
|
187
|
+
// Assistant message with tool calls
|
|
188
|
+
return {
|
|
189
|
+
role: "assistant" as const,
|
|
190
|
+
content: msg.content || null,
|
|
191
|
+
tool_calls: msg.toolCalls.map((tc) => ({
|
|
192
|
+
id: tc.id,
|
|
193
|
+
type: "function" as const,
|
|
194
|
+
function: {
|
|
195
|
+
name: tc.name,
|
|
196
|
+
arguments: typeof tc.input === "string" ? tc.input : JSON.stringify(tc.input),
|
|
197
|
+
},
|
|
198
|
+
})),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
role: msg.role as "system" | "user" | "assistant",
|
|
203
|
+
content: msg.content,
|
|
204
|
+
};
|
|
205
|
+
},
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
// Convert LLMTool[] to OpenAI tools format
|
|
209
|
+
const tools: OpenAI.ChatCompletionTool[] = options.tools.map(
|
|
210
|
+
(tool: LLMTool) => ({
|
|
211
|
+
type: "function" as const,
|
|
212
|
+
function: {
|
|
213
|
+
name: tool.name,
|
|
214
|
+
description: tool.description,
|
|
215
|
+
parameters: tool.inputSchema,
|
|
216
|
+
},
|
|
217
|
+
}),
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
// Convert tool choice
|
|
221
|
+
let tool_choice: OpenAI.ChatCompletionToolChoiceOption | undefined;
|
|
222
|
+
if (options.toolChoice === "auto") {
|
|
223
|
+
tool_choice = "auto";
|
|
224
|
+
} else if (options.toolChoice === "required") {
|
|
225
|
+
tool_choice = "required";
|
|
226
|
+
} else if (options.toolChoice === "none") {
|
|
227
|
+
tool_choice = "none";
|
|
228
|
+
} else if (options.toolChoice && typeof options.toolChoice === "object") {
|
|
229
|
+
tool_choice = {
|
|
230
|
+
type: "function",
|
|
231
|
+
function: { name: options.toolChoice.function.name },
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Call OpenAI API
|
|
236
|
+
const response = await this.client.chat.completions.create({
|
|
237
|
+
model,
|
|
238
|
+
messages: openaiMessages,
|
|
239
|
+
tools,
|
|
240
|
+
tool_choice,
|
|
241
|
+
temperature: options?.temperature,
|
|
242
|
+
max_tokens: options?.maxTokens ?? this.defaultMaxTokens,
|
|
243
|
+
stop: options?.stop,
|
|
244
|
+
...(this.buildCacheRequestPatch(options) as Record<string, unknown>),
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const choice = response.choices[0];
|
|
248
|
+
const content = choice?.message?.content ?? "";
|
|
249
|
+
|
|
250
|
+
// Extract tool calls if any
|
|
251
|
+
const toolCalls: LLMToolCall[] = [];
|
|
252
|
+
if (choice?.message?.tool_calls) {
|
|
253
|
+
for (const tc of choice.message.tool_calls) {
|
|
254
|
+
try {
|
|
255
|
+
const input = JSON.parse(tc.function.arguments);
|
|
256
|
+
toolCalls.push({
|
|
257
|
+
id: tc.id,
|
|
258
|
+
name: tc.function.name,
|
|
259
|
+
input,
|
|
260
|
+
});
|
|
261
|
+
} catch (error) {
|
|
262
|
+
// Failed to parse tool arguments - skip this tool call
|
|
263
|
+
console.warn("Failed to parse tool arguments", {
|
|
264
|
+
toolName: tc.function.name,
|
|
265
|
+
error: error instanceof Error ? error.message : String(error),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Map OpenAI finish_reason to normalized stopReason
|
|
272
|
+
const finishReason = choice?.finish_reason;
|
|
273
|
+
const stopReason = finishReason === 'stop' ? 'end_turn'
|
|
274
|
+
: finishReason === 'tool_calls' ? 'tool_use'
|
|
275
|
+
: finishReason === 'length' ? 'max_tokens'
|
|
276
|
+
: finishReason ?? undefined;
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
content,
|
|
280
|
+
usage: {
|
|
281
|
+
promptTokens: response.usage?.prompt_tokens ?? 0,
|
|
282
|
+
completionTokens: response.usage?.completion_tokens ?? 0,
|
|
283
|
+
cacheReadTokens:
|
|
284
|
+
(response.usage as unknown as { prompt_tokens_details?: { cached_tokens?: number } })
|
|
285
|
+
?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
286
|
+
providerUsage: response.usage as unknown as Record<string, unknown>,
|
|
287
|
+
},
|
|
288
|
+
model: response.model,
|
|
289
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
290
|
+
stopReason,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Create OpenAI LLM adapter.
|
|
297
|
+
* This is the factory function called by initPlatform() when loading adapters.
|
|
298
|
+
*/
|
|
299
|
+
export function createAdapter(config?: OpenAILLMConfig): OpenAILLM {
|
|
300
|
+
return new OpenAILLM(config);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Default export for direct import
|
|
304
|
+
export default createAdapter;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @kb-labs/adapters-openai/manifest
|
|
3
|
+
* Adapter manifest for OpenAI LLM.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { AdapterManifest } from "@kb-labs/core-platform";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Adapter manifest for OpenAI LLM.
|
|
10
|
+
*/
|
|
11
|
+
export const manifest: AdapterManifest = {
|
|
12
|
+
manifestVersion: "1.0.0",
|
|
13
|
+
id: "openai-llm",
|
|
14
|
+
name: "OpenAI LLM",
|
|
15
|
+
version: "1.0.0",
|
|
16
|
+
description: "OpenAI language model adapter (GPT-4, GPT-3.5, etc.)",
|
|
17
|
+
author: "KB Labs Team",
|
|
18
|
+
license: "KBPL-1.1",
|
|
19
|
+
type: "core",
|
|
20
|
+
implements: "ILLM",
|
|
21
|
+
capabilities: {
|
|
22
|
+
streaming: true,
|
|
23
|
+
custom: {
|
|
24
|
+
functionCalling: true,
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
configSchema: {
|
|
28
|
+
apiKey: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "OpenAI API key (defaults to OPENAI_API_KEY env var)",
|
|
31
|
+
},
|
|
32
|
+
model: {
|
|
33
|
+
type: "string",
|
|
34
|
+
default: "gpt-4o",
|
|
35
|
+
description: "Model to use (gpt-4o, gpt-4-turbo, gpt-3.5-turbo, etc.)",
|
|
36
|
+
},
|
|
37
|
+
temperature: {
|
|
38
|
+
type: "number",
|
|
39
|
+
default: 0.7,
|
|
40
|
+
description: "Sampling temperature (0.0 to 2.0)",
|
|
41
|
+
},
|
|
42
|
+
maxTokens: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Maximum tokens to generate",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# @kb-labs/adapters-pino
|
|
2
|
+
|
|
3
|
+
> Part of [KB Labs](https://github.com/KirillBaranov/kb-labs) ecosystem. Works exclusively within KB Labs platform.
|
|
4
|
+
|
|
5
|
+
Production-ready structured logger based on Pino with streaming and analytics integration.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
| Property | Value |
|
|
10
|
+
|----------|-------|
|
|
11
|
+
| **Implements** | `ILogger` |
|
|
12
|
+
| **Type** | `core` |
|
|
13
|
+
| **Requires** | None (optional: `analytics`) |
|
|
14
|
+
| **Category** | Logging |
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Structured Logging** - JSON-formatted logs with context
|
|
19
|
+
- **High Performance** - Built on Pino (fastest Node.js logger)
|
|
20
|
+
- **Log Levels** - trace, debug, info, warn, error, fatal
|
|
21
|
+
- **Pretty Printing** - Human-readable output for development
|
|
22
|
+
- **Streaming Support** - Buffered log streaming
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add @kb-labs/adapters-pino
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Configuration
|
|
31
|
+
|
|
32
|
+
Add to your `kb.config.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"platform": {
|
|
37
|
+
"adapters": {
|
|
38
|
+
"logger": "@kb-labs/adapters-pino"
|
|
39
|
+
},
|
|
40
|
+
"adapterOptions": {
|
|
41
|
+
"logger": {
|
|
42
|
+
"level": "info",
|
|
43
|
+
"pretty": false,
|
|
44
|
+
"streaming": {
|
|
45
|
+
"enabled": true,
|
|
46
|
+
"bufferSize": 1000,
|
|
47
|
+
"bufferMaxAge": 3600000
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Options
|
|
56
|
+
|
|
57
|
+
| Option | Type | Default | Description |
|
|
58
|
+
|--------|------|---------|-------------|
|
|
59
|
+
| `level` | `string` | `"info"` | Minimum log level |
|
|
60
|
+
| `pretty` | `boolean` | `false` | Enable pretty printing for development |
|
|
61
|
+
| `streaming.enabled` | `boolean` | `false` | Enable log streaming/buffering |
|
|
62
|
+
| `streaming.bufferSize` | `number` | `1000` | Buffer size for streaming |
|
|
63
|
+
| `streaming.bufferMaxAge` | `number` | `3600000` | Max age of buffered logs (1 hour) |
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
### Via Platform (Recommended)
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { usePlatform } from '@kb-labs/sdk';
|
|
71
|
+
|
|
72
|
+
const platform = usePlatform();
|
|
73
|
+
|
|
74
|
+
// Basic logging
|
|
75
|
+
platform.logger.info('Server started', { port: 3000 });
|
|
76
|
+
platform.logger.error('Request failed', { error, requestId });
|
|
77
|
+
|
|
78
|
+
// With child logger
|
|
79
|
+
const reqLogger = platform.logger.child({ requestId: 'req-123' });
|
|
80
|
+
reqLogger.info('Processing request');
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Standalone (Testing/Development)
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { createAdapter } from '@kb-labs/adapters-pino';
|
|
87
|
+
|
|
88
|
+
const logger = createAdapter({
|
|
89
|
+
level: 'debug',
|
|
90
|
+
pretty: true
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
logger.info('Hello, world!');
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Adapter Manifest
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
{
|
|
100
|
+
id: 'pino-logger',
|
|
101
|
+
name: 'Pino Logger',
|
|
102
|
+
version: '1.0.0',
|
|
103
|
+
implements: 'ILogger',
|
|
104
|
+
optional: {
|
|
105
|
+
adapters: ['analytics'],
|
|
106
|
+
},
|
|
107
|
+
capabilities: {
|
|
108
|
+
streaming: true,
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Log Levels
|
|
114
|
+
|
|
115
|
+
| Level | When to use |
|
|
116
|
+
|-------|-------------|
|
|
117
|
+
| `trace` | Very detailed debugging info |
|
|
118
|
+
| `debug` | Debugging information |
|
|
119
|
+
| `info` | General operational events |
|
|
120
|
+
| `warn` | Warning conditions |
|
|
121
|
+
| `error` | Error conditions |
|
|
122
|
+
| `fatal` | System is unusable |
|
|
123
|
+
|
|
124
|
+
## FAQ
|
|
125
|
+
|
|
126
|
+
<details>
|
|
127
|
+
<summary><strong>Q: How do I enable pretty printing in development?</strong></summary>
|
|
128
|
+
|
|
129
|
+
Set `pretty: true` in config or use environment:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
KB_LOG_PRETTY=true pnpm dev
|
|
133
|
+
```
|
|
134
|
+
</details>
|
|
135
|
+
|
|
136
|
+
<details>
|
|
137
|
+
<summary><strong>Q: How do I send logs to remote service?</strong></summary>
|
|
138
|
+
|
|
139
|
+
Use `@kb-labs/adapters-pino-http` as a transport to stream logs to REST API.
|
|
140
|
+
</details>
|
|
141
|
+
|
|
142
|
+
## Related Adapters
|
|
143
|
+
|
|
144
|
+
| Adapter | Use Case |
|
|
145
|
+
|---------|----------|
|
|
146
|
+
| `@kb-labs/adapters-pino-http` | HTTP transport for remote logging |
|
|
147
|
+
| `@kb-labs/adapters-log-ringbuffer` | In-memory log streaming |
|
|
148
|
+
| `@kb-labs/adapters-log-sqlite` | Persistent log storage |
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
[KB Public License v1.1](../../LICENSE) - KB Labs Team
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard ESLint configuration template
|
|
3
|
+
*
|
|
4
|
+
* This is the canonical template for all @kb-labs packages.
|
|
5
|
+
* DO NOT modify this file locally - it is synced from @kb-labs/devkit
|
|
6
|
+
*
|
|
7
|
+
* Customization guidelines:
|
|
8
|
+
* - DevKit preset already includes all standard ignores
|
|
9
|
+
* - Only add project-specific ignores if absolutely necessary
|
|
10
|
+
* - Document why custom ignores are needed
|
|
11
|
+
*
|
|
12
|
+
* @see https://github.com/kb-labs/devkit#eslint-configuration
|
|
13
|
+
*/
|
|
14
|
+
import nodePreset from '@kb-labs/devkit/eslint/node.js';
|
|
15
|
+
|
|
16
|
+
export default [
|
|
17
|
+
...nodePreset,
|
|
18
|
+
|
|
19
|
+
// OPTIONAL: Add project-specific ignores only if needed
|
|
20
|
+
// DevKit preset already ignores: dist/, coverage/, node_modules/, *.d.ts, scripts/, etc.
|
|
21
|
+
// {
|
|
22
|
+
// ignores: [
|
|
23
|
+
// // Add ONLY project-specific patterns here
|
|
24
|
+
// // Example: '**/*.generated.ts',
|
|
25
|
+
// ]
|
|
26
|
+
// }
|
|
27
|
+
];
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kb-labs/adapters-pino",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Pino adapter implementing ILogger interface",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"scripts": {
|
|
20
|
+
"clean": "rimraf dist",
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"dev": "tsup --watch",
|
|
23
|
+
"type-check": "tsc --noEmit",
|
|
24
|
+
"test": "vitest run --passWithNoTests",
|
|
25
|
+
"test:watch": "vitest",
|
|
26
|
+
"lint": "eslint src --ext .ts",
|
|
27
|
+
"lint:fix": "eslint . --fix"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"pino": "^9.0.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"@kb-labs/core-platform": "*"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@kb-labs/core-platform": "link:../../../../platform/kb-labs-core/packages/core-platform",
|
|
37
|
+
"@types/node": "^24.3.3",
|
|
38
|
+
"eslint": "^9",
|
|
39
|
+
"tsup": "^8.5.0",
|
|
40
|
+
"typescript": "^5.6.3",
|
|
41
|
+
"vitest": "^3.2.4",
|
|
42
|
+
"@kb-labs/devkit": "link:../../../kb-labs-devkit",
|
|
43
|
+
"rimraf": "^6.0.1"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20.0.0",
|
|
47
|
+
"pnpm": ">=9.0.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { PinoLoggerAdapter } from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('PinoLoggerAdapter', () => {
|
|
5
|
+
it('includes child bindings in onLog records', () => {
|
|
6
|
+
const logger = new PinoLoggerAdapter({ level: 'debug' });
|
|
7
|
+
const callback = vi.fn();
|
|
8
|
+
logger.onLog(callback);
|
|
9
|
+
|
|
10
|
+
const child = logger.child({
|
|
11
|
+
traceId: 'trace-1',
|
|
12
|
+
requestId: 'req-1',
|
|
13
|
+
invocationId: 'inv-1',
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
child.info('hello', { step: 'start' });
|
|
17
|
+
|
|
18
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
19
|
+
const [record] = callback.mock.calls[0]!;
|
|
20
|
+
expect(record.fields).toMatchObject({
|
|
21
|
+
traceId: 'trace-1',
|
|
22
|
+
requestId: 'req-1',
|
|
23
|
+
invocationId: 'inv-1',
|
|
24
|
+
step: 'start',
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('propagates nested child bindings in onLog records', () => {
|
|
29
|
+
const logger = new PinoLoggerAdapter({ level: 'debug' });
|
|
30
|
+
const callback = vi.fn();
|
|
31
|
+
logger.onLog(callback);
|
|
32
|
+
|
|
33
|
+
const child = logger.child({ traceId: 'trace-1' }).child({ spanId: 'span-2' });
|
|
34
|
+
child.debug('nested');
|
|
35
|
+
|
|
36
|
+
expect(callback).toHaveBeenCalledTimes(1);
|
|
37
|
+
const [record] = callback.mock.calls[0]!;
|
|
38
|
+
expect(record.fields).toMatchObject({
|
|
39
|
+
traceId: 'trace-1',
|
|
40
|
+
spanId: 'span-2',
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|