@tachu/extensions 1.0.0-beta.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 (152) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/LICENSE +201 -0
  3. package/README.md +825 -0
  4. package/README_ZH.md +815 -0
  5. package/dist/backends/file.d.ts +18 -0
  6. package/dist/backends/file.d.ts.map +1 -0
  7. package/dist/backends/file.js +69 -0
  8. package/dist/backends/file.js.map +1 -0
  9. package/dist/backends/index.d.ts +4 -0
  10. package/dist/backends/index.d.ts.map +1 -0
  11. package/dist/backends/index.js +4 -0
  12. package/dist/backends/index.js.map +1 -0
  13. package/dist/backends/terminal.d.ts +18 -0
  14. package/dist/backends/terminal.d.ts.map +1 -0
  15. package/dist/backends/terminal.js +57 -0
  16. package/dist/backends/terminal.js.map +1 -0
  17. package/dist/backends/web.d.ts +18 -0
  18. package/dist/backends/web.d.ts.map +1 -0
  19. package/dist/backends/web.js +53 -0
  20. package/dist/backends/web.js.map +1 -0
  21. package/dist/common/net.d.ts +31 -0
  22. package/dist/common/net.d.ts.map +1 -0
  23. package/dist/common/net.js +162 -0
  24. package/dist/common/net.js.map +1 -0
  25. package/dist/common/path.d.ts +18 -0
  26. package/dist/common/path.d.ts.map +1 -0
  27. package/dist/common/path.js +34 -0
  28. package/dist/common/path.js.map +1 -0
  29. package/dist/common/process.d.ts +19 -0
  30. package/dist/common/process.d.ts.map +1 -0
  31. package/dist/common/process.js +67 -0
  32. package/dist/common/process.js.map +1 -0
  33. package/dist/index.d.ts +9 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +9 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/mcp/index.d.ts +3 -0
  38. package/dist/mcp/index.d.ts.map +1 -0
  39. package/dist/mcp/index.js +3 -0
  40. package/dist/mcp/index.js.map +1 -0
  41. package/dist/mcp/sse-adapter.d.ts +70 -0
  42. package/dist/mcp/sse-adapter.d.ts.map +1 -0
  43. package/dist/mcp/sse-adapter.js +176 -0
  44. package/dist/mcp/sse-adapter.js.map +1 -0
  45. package/dist/mcp/stdio-adapter.d.ts +73 -0
  46. package/dist/mcp/stdio-adapter.d.ts.map +1 -0
  47. package/dist/mcp/stdio-adapter.js +178 -0
  48. package/dist/mcp/stdio-adapter.js.map +1 -0
  49. package/dist/observability/index.d.ts +3 -0
  50. package/dist/observability/index.d.ts.map +1 -0
  51. package/dist/observability/index.js +3 -0
  52. package/dist/observability/index.js.map +1 -0
  53. package/dist/observability/jsonl-emitter.d.ts +58 -0
  54. package/dist/observability/jsonl-emitter.d.ts.map +1 -0
  55. package/dist/observability/jsonl-emitter.js +96 -0
  56. package/dist/observability/jsonl-emitter.js.map +1 -0
  57. package/dist/observability/otel-emitter.d.ts +52 -0
  58. package/dist/observability/otel-emitter.d.ts.map +1 -0
  59. package/dist/observability/otel-emitter.js +143 -0
  60. package/dist/observability/otel-emitter.js.map +1 -0
  61. package/dist/providers/anthropic.d.ts +54 -0
  62. package/dist/providers/anthropic.d.ts.map +1 -0
  63. package/dist/providers/anthropic.js +298 -0
  64. package/dist/providers/anthropic.js.map +1 -0
  65. package/dist/providers/index.d.ts +4 -0
  66. package/dist/providers/index.d.ts.map +1 -0
  67. package/dist/providers/index.js +4 -0
  68. package/dist/providers/index.js.map +1 -0
  69. package/dist/providers/mock.d.ts +38 -0
  70. package/dist/providers/mock.d.ts.map +1 -0
  71. package/dist/providers/mock.js +79 -0
  72. package/dist/providers/mock.js.map +1 -0
  73. package/dist/providers/openai.d.ts +61 -0
  74. package/dist/providers/openai.d.ts.map +1 -0
  75. package/dist/providers/openai.js +299 -0
  76. package/dist/providers/openai.js.map +1 -0
  77. package/dist/rules/index.d.ts +9 -0
  78. package/dist/rules/index.d.ts.map +1 -0
  79. package/dist/rules/index.js +15 -0
  80. package/dist/rules/index.js.map +1 -0
  81. package/dist/rules/no-hallucination.md +11 -0
  82. package/dist/rules/no-sensitive-output.md +11 -0
  83. package/dist/rules/prefer-concise-response.md +11 -0
  84. package/dist/rules/require-tool-verification.md +11 -0
  85. package/dist/tools/apply-patch/descriptor.md +27 -0
  86. package/dist/tools/apply-patch/executor.d.ts +19 -0
  87. package/dist/tools/apply-patch/executor.d.ts.map +1 -0
  88. package/dist/tools/apply-patch/executor.js +190 -0
  89. package/dist/tools/apply-patch/executor.js.map +1 -0
  90. package/dist/tools/fetch-url/descriptor.md +38 -0
  91. package/dist/tools/fetch-url/executor.d.ts +20 -0
  92. package/dist/tools/fetch-url/executor.d.ts.map +1 -0
  93. package/dist/tools/fetch-url/executor.js +34 -0
  94. package/dist/tools/fetch-url/executor.js.map +1 -0
  95. package/dist/tools/index.d.ts +12 -0
  96. package/dist/tools/index.d.ts.map +1 -0
  97. package/dist/tools/index.js +191 -0
  98. package/dist/tools/index.js.map +1 -0
  99. package/dist/tools/list-dir/descriptor.md +29 -0
  100. package/dist/tools/list-dir/executor.d.ts +22 -0
  101. package/dist/tools/list-dir/executor.d.ts.map +1 -0
  102. package/dist/tools/list-dir/executor.js +46 -0
  103. package/dist/tools/list-dir/executor.js.map +1 -0
  104. package/dist/tools/read-file/descriptor.md +28 -0
  105. package/dist/tools/read-file/executor.d.ts +15 -0
  106. package/dist/tools/read-file/executor.d.ts.map +1 -0
  107. package/dist/tools/read-file/executor.js +22 -0
  108. package/dist/tools/read-file/executor.js.map +1 -0
  109. package/dist/tools/run-shell/descriptor.md +39 -0
  110. package/dist/tools/run-shell/executor.d.ts +20 -0
  111. package/dist/tools/run-shell/executor.d.ts.map +1 -0
  112. package/dist/tools/run-shell/executor.js +76 -0
  113. package/dist/tools/run-shell/executor.js.map +1 -0
  114. package/dist/tools/search-code/descriptor.md +31 -0
  115. package/dist/tools/search-code/executor.d.ts +23 -0
  116. package/dist/tools/search-code/executor.d.ts.map +1 -0
  117. package/dist/tools/search-code/executor.js +113 -0
  118. package/dist/tools/search-code/executor.js.map +1 -0
  119. package/dist/tools/shared.d.ts +21 -0
  120. package/dist/tools/shared.d.ts.map +1 -0
  121. package/dist/tools/shared.js +12 -0
  122. package/dist/tools/shared.js.map +1 -0
  123. package/dist/tools/write-file/descriptor.md +30 -0
  124. package/dist/tools/write-file/executor.d.ts +16 -0
  125. package/dist/tools/write-file/executor.d.ts.map +1 -0
  126. package/dist/tools/write-file/executor.js +18 -0
  127. package/dist/tools/write-file/executor.js.map +1 -0
  128. package/dist/transformers/document-to-text.d.ts +23 -0
  129. package/dist/transformers/document-to-text.d.ts.map +1 -0
  130. package/dist/transformers/document-to-text.js +69 -0
  131. package/dist/transformers/document-to-text.js.map +1 -0
  132. package/dist/transformers/image-to-text.d.ts +38 -0
  133. package/dist/transformers/image-to-text.d.ts.map +1 -0
  134. package/dist/transformers/image-to-text.js +81 -0
  135. package/dist/transformers/image-to-text.js.map +1 -0
  136. package/dist/transformers/index.d.ts +3 -0
  137. package/dist/transformers/index.d.ts.map +1 -0
  138. package/dist/transformers/index.js +3 -0
  139. package/dist/transformers/index.js.map +1 -0
  140. package/dist/vector/index.d.ts +3 -0
  141. package/dist/vector/index.d.ts.map +1 -0
  142. package/dist/vector/index.js +3 -0
  143. package/dist/vector/index.js.map +1 -0
  144. package/dist/vector/local-fs.d.ts +76 -0
  145. package/dist/vector/local-fs.d.ts.map +1 -0
  146. package/dist/vector/local-fs.js +153 -0
  147. package/dist/vector/local-fs.js.map +1 -0
  148. package/dist/vector/qdrant.d.ts +65 -0
  149. package/dist/vector/qdrant.d.ts.map +1 -0
  150. package/dist/vector/qdrant.js +176 -0
  151. package/dist/vector/qdrant.js.map +1 -0
  152. package/package.json +74 -0
@@ -0,0 +1,96 @@
1
+ import { mkdir, rename, stat, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ /**
4
+ * JSON Lines 文件事件发射器。
5
+ */
6
+ export class JsonlEmitter {
7
+ handlers = new Map();
8
+ filePath;
9
+ rotateSize;
10
+ masker = (payload) => payload;
11
+ writeQueue = Promise.resolve();
12
+ /**
13
+ * 创建 JSONL 发射器。
14
+ *
15
+ * @param options 文件配置
16
+ */
17
+ constructor(options) {
18
+ this.filePath = options.filePath;
19
+ this.rotateSize = options.rotateSize ?? 10 * 1024 * 1024;
20
+ }
21
+ /**
22
+ * 订阅事件。
23
+ *
24
+ * @param type 事件类型
25
+ * @param handler 处理器
26
+ * @returns 取消订阅函数
27
+ */
28
+ on(type, handler) {
29
+ const bucket = this.handlers.get(type) ?? new Set();
30
+ bucket.add(handler);
31
+ this.handlers.set(type, bucket);
32
+ return () => this.off(type, handler);
33
+ }
34
+ /**
35
+ * 取消订阅。
36
+ *
37
+ * @param type 事件类型
38
+ * @param handler 处理器
39
+ */
40
+ off(type, handler) {
41
+ const bucket = this.handlers.get(type);
42
+ bucket?.delete(handler);
43
+ if (bucket && bucket.size === 0) {
44
+ this.handlers.delete(type);
45
+ }
46
+ }
47
+ /**
48
+ * 发射并持久化事件。
49
+ *
50
+ * @param event 引擎事件
51
+ */
52
+ emit(event) {
53
+ const maskedEvent = {
54
+ ...event,
55
+ payload: this.masker(event.payload),
56
+ };
57
+ this.emitToSubscribers(maskedEvent);
58
+ this.writeQueue = this.writeQueue.then(() => this.append(maskedEvent)).catch(() => undefined);
59
+ }
60
+ /**
61
+ * 设置脱敏函数。
62
+ *
63
+ * @param masker 脱敏函数
64
+ */
65
+ setMasker(masker) {
66
+ this.masker = masker;
67
+ }
68
+ /**
69
+ * 等待队列写入完成。
70
+ */
71
+ async dispose() {
72
+ await this.writeQueue;
73
+ }
74
+ emitToSubscribers(event) {
75
+ for (const handler of this.handlers.get(event.type) ?? []) {
76
+ handler(event);
77
+ }
78
+ for (const handler of this.handlers.get("*") ?? []) {
79
+ handler(event);
80
+ }
81
+ }
82
+ async append(event) {
83
+ await mkdir(dirname(this.filePath), { recursive: true });
84
+ await this.rotateIfNeeded();
85
+ await writeFile(this.filePath, `${JSON.stringify(event)}\n`, { flag: "a" });
86
+ }
87
+ async rotateIfNeeded() {
88
+ const info = await stat(this.filePath).catch(() => null);
89
+ if (!info || info.size < this.rotateSize) {
90
+ return;
91
+ }
92
+ const rotatedPath = `${this.filePath}.${Date.now()}.jsonl`;
93
+ await rename(this.filePath, rotatedPath);
94
+ }
95
+ }
96
+ //# sourceMappingURL=jsonl-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonl-emitter.js","sourceRoot":"","sources":["../../src/observability/jsonl-emitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { EngineEvent, ObservabilityEmitter } from "@tachu/core";
2
+ import type { Tracer } from "@opentelemetry/api";
3
+ type EventHandler = (event: EngineEvent) => void;
4
+ /**
5
+ * 基于 OpenTelemetry 的 ObservabilityEmitter 实现。
6
+ */
7
+ export declare class OtelEmitter implements ObservabilityEmitter {
8
+ private readonly options;
9
+ private readonly handlers;
10
+ private readonly phaseSpans;
11
+ private masker;
12
+ /**
13
+ * 创建 OTel 发射器。
14
+ *
15
+ * @param options 构造参数
16
+ */
17
+ constructor(options: {
18
+ tracer: Tracer;
19
+ });
20
+ /**
21
+ * 订阅事件。
22
+ *
23
+ * @param type 事件类型
24
+ * @param handler 处理器
25
+ * @returns 取消订阅函数
26
+ */
27
+ on(type: EngineEvent["type"] | "*", handler: EventHandler): () => void;
28
+ /**
29
+ * 取消订阅。
30
+ *
31
+ * @param type 事件类型
32
+ * @param handler 处理器
33
+ */
34
+ off(type: EngineEvent["type"] | "*", handler: EventHandler): void;
35
+ /**
36
+ * 发射事件并映射到 OTel Span。
37
+ *
38
+ * @param event 引擎事件
39
+ */
40
+ emit(event: EngineEvent): void;
41
+ /**
42
+ * 配置 payload 脱敏函数。
43
+ *
44
+ * @param masker 脱敏函数
45
+ */
46
+ setMasker(masker: (payload: unknown) => unknown): void;
47
+ private emitToSubscribers;
48
+ private emitToOtel;
49
+ private setIfPresent;
50
+ }
51
+ export {};
52
+ //# sourceMappingURL=otel-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-emitter.d.ts","sourceRoot":"","sources":["../../src/observability/otel-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;AAEjD;;GAEG;AACH,qBAAa,WAAY,YAAW,oBAAoB;IAU1C,OAAO,CAAC,QAAQ,CAAC,OAAO;IATpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA2D;IACpF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAsD;IACjF,OAAO,CAAC,MAAM,CAAuD;IAErE;;;;OAIG;gBAC0B,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE;IAExD;;;;;;OAMG;IACH,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI;IAOtE;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,GAAG,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI;IAQjE;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAS9B;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,IAAI;IAItD,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,UAAU;IAiElB,OAAO,CAAC,YAAY;CASrB"}
@@ -0,0 +1,143 @@
1
+ import { context, trace, SpanStatusCode } from "@opentelemetry/api";
2
+ /**
3
+ * 基于 OpenTelemetry 的 ObservabilityEmitter 实现。
4
+ */
5
+ export class OtelEmitter {
6
+ options;
7
+ handlers = new Map();
8
+ phaseSpans = new Map();
9
+ masker = (payload) => payload;
10
+ /**
11
+ * 创建 OTel 发射器。
12
+ *
13
+ * @param options 构造参数
14
+ */
15
+ constructor(options) {
16
+ this.options = options;
17
+ }
18
+ /**
19
+ * 订阅事件。
20
+ *
21
+ * @param type 事件类型
22
+ * @param handler 处理器
23
+ * @returns 取消订阅函数
24
+ */
25
+ on(type, handler) {
26
+ const bucket = this.handlers.get(type) ?? new Set();
27
+ bucket.add(handler);
28
+ this.handlers.set(type, bucket);
29
+ return () => this.off(type, handler);
30
+ }
31
+ /**
32
+ * 取消订阅。
33
+ *
34
+ * @param type 事件类型
35
+ * @param handler 处理器
36
+ */
37
+ off(type, handler) {
38
+ const bucket = this.handlers.get(type);
39
+ bucket?.delete(handler);
40
+ if (bucket && bucket.size === 0) {
41
+ this.handlers.delete(type);
42
+ }
43
+ }
44
+ /**
45
+ * 发射事件并映射到 OTel Span。
46
+ *
47
+ * @param event 引擎事件
48
+ */
49
+ emit(event) {
50
+ const maskedEvent = {
51
+ ...event,
52
+ payload: this.masker(event.payload),
53
+ };
54
+ this.emitToSubscribers(maskedEvent);
55
+ this.emitToOtel(maskedEvent);
56
+ }
57
+ /**
58
+ * 配置 payload 脱敏函数。
59
+ *
60
+ * @param masker 脱敏函数
61
+ */
62
+ setMasker(masker) {
63
+ this.masker = masker;
64
+ }
65
+ emitToSubscribers(event) {
66
+ for (const handler of this.handlers.get(event.type) ?? []) {
67
+ handler(event);
68
+ }
69
+ for (const handler of this.handlers.get("*") ?? []) {
70
+ handler(event);
71
+ }
72
+ }
73
+ emitToOtel(event) {
74
+ const phaseKey = `${event.traceId}:${event.sessionId}:${event.phase}`;
75
+ if (event.type === "phase_enter" || event.type === "phase-start") {
76
+ const span = this.options.tracer.startSpan(`phase:${event.phase}`, {
77
+ attributes: {
78
+ "engine.trace_id": event.traceId,
79
+ "engine.session_id": event.sessionId,
80
+ "engine.phase": event.phase,
81
+ },
82
+ startTime: event.timestamp,
83
+ });
84
+ this.phaseSpans.set(phaseKey, span);
85
+ return;
86
+ }
87
+ if (event.type === "phase_exit" || event.type === "phase-end") {
88
+ const span = this.phaseSpans.get(phaseKey);
89
+ if (span) {
90
+ if (event.payload.error) {
91
+ span.recordException(event.payload.error);
92
+ span.setStatus({ code: SpanStatusCode.ERROR, message: "phase failed" });
93
+ }
94
+ else {
95
+ span.setStatus({ code: SpanStatusCode.OK });
96
+ }
97
+ span.end(event.timestamp);
98
+ this.phaseSpans.delete(phaseKey);
99
+ }
100
+ return;
101
+ }
102
+ const parent = this.phaseSpans.get(phaseKey);
103
+ const parentContext = parent ? trace.setSpan(context.active(), parent) : context.active();
104
+ const span = this.options.tracer.startSpan(`event:${event.type}`, {
105
+ attributes: {
106
+ "engine.trace_id": event.traceId,
107
+ "engine.session_id": event.sessionId,
108
+ "engine.phase": event.phase,
109
+ "engine.event_type": event.type,
110
+ },
111
+ startTime: event.timestamp,
112
+ }, parentContext);
113
+ if (event.type.startsWith("llm")) {
114
+ this.setIfPresent(span, "llm.provider", event.payload.provider);
115
+ this.setIfPresent(span, "llm.model", event.payload.model);
116
+ this.setIfPresent(span, "llm.tokens.prompt", event.payload.promptTokens);
117
+ this.setIfPresent(span, "llm.tokens.completion", event.payload.completionTokens);
118
+ }
119
+ if (event.type.startsWith("tool")) {
120
+ this.setIfPresent(span, "tool.name", event.payload.name);
121
+ this.setIfPresent(span, "tool.side_effect", event.payload.sideEffect);
122
+ }
123
+ if (event.type === "error" || event.payload.error) {
124
+ span.setStatus({ code: SpanStatusCode.ERROR, message: "engine error" });
125
+ if (event.payload.error instanceof Error) {
126
+ span.recordException(event.payload.error);
127
+ }
128
+ else if (event.payload.error) {
129
+ span.recordException(new Error(String(event.payload.error)));
130
+ }
131
+ }
132
+ else {
133
+ span.setStatus({ code: SpanStatusCode.OK });
134
+ }
135
+ span.end(event.timestamp);
136
+ }
137
+ setIfPresent(span, key, value) {
138
+ if (value !== undefined) {
139
+ span.setAttribute(key, value);
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=otel-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel-emitter.js","sourceRoot":"","sources":["../../src/observability/otel-emitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type ChatRequest, type ChatResponse, type ChatStreamChunk, type Message, type ModelInfo, type ProviderAdapter } from "@tachu/core";
2
+ interface AnthropicProviderOptions {
3
+ apiKey?: string;
4
+ baseURL?: string;
5
+ timeoutMs?: number;
6
+ }
7
+ /**
8
+ * Anthropic 官方 Provider Adapter。
9
+ */
10
+ export declare class AnthropicProviderAdapter implements ProviderAdapter {
11
+ readonly id = "anthropic";
12
+ readonly name = "Anthropic";
13
+ private readonly client;
14
+ private readonly timeoutMs;
15
+ /**
16
+ * 创建 Anthropic Provider。
17
+ *
18
+ * @param options Provider 配置
19
+ * @throws ProviderError 缺失凭据时抛出
20
+ */
21
+ constructor(options?: AnthropicProviderOptions);
22
+ /**
23
+ * 返回 Anthropic 已知模型清单(官方暂未公开统一 list endpoint)。
24
+ *
25
+ * @returns 模型列表
26
+ */
27
+ listAvailableModels(): Promise<ModelInfo[]>;
28
+ /**
29
+ * 发起非流式对话请求。
30
+ *
31
+ * @param request 对话请求
32
+ * @param signal 可选取消信号
33
+ * @returns 对话响应
34
+ */
35
+ chat(request: ChatRequest, signal?: AbortSignal): Promise<ChatResponse>;
36
+ /**
37
+ * 发起流式对话请求。
38
+ *
39
+ * @param request 对话请求
40
+ * @param signal 可选取消信号
41
+ * @returns 流式分片
42
+ */
43
+ chatStream(request: ChatRequest, signal?: AbortSignal): AsyncIterable<ChatStreamChunk>;
44
+ /**
45
+ * 调用官方 countTokens 接口做精确计数。
46
+ *
47
+ * @param messages 消息列表
48
+ * @param model 模型名
49
+ * @returns token 数
50
+ */
51
+ countTokens(messages: Message[], model: string): Promise<number>;
52
+ }
53
+ export {};
54
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/providers/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,OAAO,EACZ,KAAK,SAAS,EACd,KAAK,eAAe,EAErB,MAAM,aAAa,CAAC;AAIrB,UAAU,wBAAwB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAsHD;;GAEG;AACH,qBAAa,wBAAyB,YAAW,eAAe;IAC9D,QAAQ,CAAC,EAAE,eAAe;IAC1B,QAAQ,CAAC,IAAI,eAAe;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC;;;;;OAKG;gBACS,OAAO,GAAE,wBAA6B;IAelD;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAIjD;;;;;;OAMG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAyE7E;;;;;;OAMG;IACI,UAAU,CACf,OAAO,EAAE,WAAW,EACpB,MAAM,CAAC,EAAE,WAAW,GACnB,aAAa,CAAC,eAAe,CAAC;IAuEjC;;;;;;OAMG;IACG,WAAW,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAYvE"}
@@ -0,0 +1,298 @@
1
+ import Anthropic from "@anthropic-ai/sdk";
2
+ import { ProviderError, TimeoutError, } from "@tachu/core";
3
+ import { withAbortTimeout } from "../common/net";
4
+ const DEFAULT_TIMEOUT_MS = 60_000;
5
+ const KNOWN_MODELS = [
6
+ {
7
+ modelName: "claude-3-5-sonnet-latest",
8
+ capabilities: {
9
+ supportedModalities: ["text", "image"],
10
+ maxContextTokens: 200_000,
11
+ supportsStreaming: true,
12
+ supportsFunctionCalling: true,
13
+ },
14
+ },
15
+ {
16
+ modelName: "claude-3-5-haiku-latest",
17
+ capabilities: {
18
+ supportedModalities: ["text", "image"],
19
+ maxContextTokens: 200_000,
20
+ supportsStreaming: true,
21
+ supportsFunctionCalling: true,
22
+ },
23
+ },
24
+ {
25
+ modelName: "claude-3-opus-latest",
26
+ capabilities: {
27
+ supportedModalities: ["text", "image"],
28
+ maxContextTokens: 200_000,
29
+ supportsStreaming: true,
30
+ supportsFunctionCalling: true,
31
+ },
32
+ },
33
+ ];
34
+ const toAnthropicTools = (tools) => tools?.map((tool) => ({
35
+ name: tool.name,
36
+ description: tool.description,
37
+ input_schema: tool.inputSchema,
38
+ }));
39
+ const toAnthropicMessages = (messages) => {
40
+ const systemSegments = [];
41
+ const converted = [];
42
+ for (const message of messages) {
43
+ if (message.role === "system") {
44
+ systemSegments.push(message.content);
45
+ continue;
46
+ }
47
+ if (message.role === "tool") {
48
+ converted.push({
49
+ role: "user",
50
+ content: [
51
+ {
52
+ type: "tool_result",
53
+ tool_use_id: message.toolCallId ?? message.name ?? "tool",
54
+ content: message.content,
55
+ },
56
+ ],
57
+ });
58
+ continue;
59
+ }
60
+ converted.push({
61
+ role: message.role === "assistant" ? "assistant" : "user",
62
+ content: message.content,
63
+ });
64
+ }
65
+ return {
66
+ system: systemSegments.length > 0 ? systemSegments.join("\n\n") : undefined,
67
+ messages: converted,
68
+ };
69
+ };
70
+ const mapProviderError = (error) => {
71
+ if (error instanceof TimeoutError || error instanceof ProviderError) {
72
+ return error;
73
+ }
74
+ const candidate = error;
75
+ const message = candidate.message ?? "Anthropic 调用失败";
76
+ if (candidate.status === 401) {
77
+ return new ProviderError("PROVIDER_AUTH_FAILED", message, { cause: error });
78
+ }
79
+ if (candidate.status === 429) {
80
+ return new ProviderError("PROVIDER_RATE_LIMITED", message, {
81
+ cause: error,
82
+ retryable: true,
83
+ });
84
+ }
85
+ if ((candidate.status ?? 0) >= 500) {
86
+ return new ProviderError("PROVIDER_UPSTREAM_ERROR", message, {
87
+ cause: error,
88
+ retryable: true,
89
+ });
90
+ }
91
+ return new ProviderError("PROVIDER_CALL_FAILED", message, {
92
+ cause: error,
93
+ retryable: true,
94
+ });
95
+ };
96
+ /**
97
+ * Anthropic 官方 Provider Adapter。
98
+ */
99
+ export class AnthropicProviderAdapter {
100
+ id = "anthropic";
101
+ name = "Anthropic";
102
+ client;
103
+ timeoutMs;
104
+ /**
105
+ * 创建 Anthropic Provider。
106
+ *
107
+ * @param options Provider 配置
108
+ * @throws ProviderError 缺失凭据时抛出
109
+ */
110
+ constructor(options = {}) {
111
+ const apiKey = options.apiKey ?? process.env.ANTHROPIC_API_KEY;
112
+ if (!apiKey) {
113
+ throw new ProviderError("PROVIDER_MISSING_CREDENTIALS", "缺少 ANTHROPIC_API_KEY 或 options.apiKey");
114
+ }
115
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
116
+ this.client = new Anthropic({
117
+ apiKey,
118
+ baseURL: options.baseURL,
119
+ });
120
+ }
121
+ /**
122
+ * 返回 Anthropic 已知模型清单(官方暂未公开统一 list endpoint)。
123
+ *
124
+ * @returns 模型列表
125
+ */
126
+ async listAvailableModels() {
127
+ return KNOWN_MODELS;
128
+ }
129
+ /**
130
+ * 发起非流式对话请求。
131
+ *
132
+ * @param request 对话请求
133
+ * @param signal 可选取消信号
134
+ * @returns 对话响应
135
+ */
136
+ async chat(request, signal) {
137
+ const extended = request;
138
+ const mapped = toAnthropicMessages(request.messages);
139
+ const timeout = withAbortTimeout(signal, this.timeoutMs);
140
+ try {
141
+ const body = {
142
+ model: request.model,
143
+ max_tokens: request.maxTokens ?? 1024,
144
+ messages: mapped.messages,
145
+ };
146
+ if (request.temperature !== undefined) {
147
+ body.temperature = request.temperature;
148
+ }
149
+ if (extended.stop) {
150
+ body.stop_sequences = extended.stop;
151
+ }
152
+ if (mapped.system) {
153
+ body.system = mapped.system;
154
+ }
155
+ const tools = toAnthropicTools(request.tools);
156
+ if (tools && tools.length > 0) {
157
+ body.tools = tools;
158
+ }
159
+ body.tool_choice =
160
+ extended.toolChoice === "required"
161
+ ? { type: "any" }
162
+ : extended.toolChoice && typeof extended.toolChoice === "object"
163
+ ? { type: "tool", name: extended.toolChoice.function.name }
164
+ : { type: "auto" };
165
+ const response = await this.client.messages.create(body, {
166
+ signal: timeout.signal,
167
+ });
168
+ const content = response.content
169
+ .map((block) => {
170
+ if (block.type === "text") {
171
+ return block.text;
172
+ }
173
+ if (block.type === "tool_use") {
174
+ return JSON.stringify({
175
+ type: "tool_use",
176
+ id: block.id,
177
+ name: block.name,
178
+ input: block.input,
179
+ });
180
+ }
181
+ return "";
182
+ })
183
+ .filter((part) => part.length > 0)
184
+ .join("\n");
185
+ return {
186
+ content,
187
+ usage: {
188
+ promptTokens: response.usage.input_tokens +
189
+ (response.usage.cache_creation_input_tokens ?? 0) +
190
+ (response.usage.cache_read_input_tokens ?? 0),
191
+ completionTokens: response.usage.output_tokens,
192
+ totalTokens: response.usage.input_tokens +
193
+ (response.usage.cache_creation_input_tokens ?? 0) +
194
+ (response.usage.cache_read_input_tokens ?? 0) +
195
+ response.usage.output_tokens,
196
+ },
197
+ };
198
+ }
199
+ catch (error) {
200
+ throw mapProviderError(error);
201
+ }
202
+ finally {
203
+ timeout.cleanup();
204
+ }
205
+ }
206
+ /**
207
+ * 发起流式对话请求。
208
+ *
209
+ * @param request 对话请求
210
+ * @param signal 可选取消信号
211
+ * @returns 流式分片
212
+ */
213
+ async *chatStream(request, signal) {
214
+ const extended = request;
215
+ const mapped = toAnthropicMessages(request.messages);
216
+ const timeout = withAbortTimeout(signal, this.timeoutMs);
217
+ try {
218
+ const stream = (await this.client.messages.create((() => {
219
+ const body = {
220
+ model: request.model,
221
+ max_tokens: request.maxTokens ?? 1024,
222
+ messages: mapped.messages,
223
+ stream: true,
224
+ };
225
+ if (request.temperature !== undefined) {
226
+ body.temperature = request.temperature;
227
+ }
228
+ if (extended.stop) {
229
+ body.stop_sequences = extended.stop;
230
+ }
231
+ if (mapped.system) {
232
+ body.system = mapped.system;
233
+ }
234
+ const tools = toAnthropicTools(request.tools);
235
+ if (tools && tools.length > 0) {
236
+ body.tools = tools;
237
+ }
238
+ body.tool_choice =
239
+ extended.toolChoice === "required"
240
+ ? { type: "any" }
241
+ : extended.toolChoice && typeof extended.toolChoice === "object"
242
+ ? { type: "tool", name: extended.toolChoice.function.name }
243
+ : { type: "auto" };
244
+ return body;
245
+ })(), {
246
+ signal: timeout.signal,
247
+ }));
248
+ for await (const event of stream) {
249
+ if (timeout.signal.aborted) {
250
+ throw timeout.signal.reason ?? new Error("aborted");
251
+ }
252
+ if (event.type === "content_block_delta") {
253
+ if (event.delta?.type === "text_delta" && typeof event.delta.text === "string") {
254
+ yield { delta: event.delta.text };
255
+ }
256
+ else if (event.delta?.type === "input_json_delta") {
257
+ yield {
258
+ delta: JSON.stringify({
259
+ type: "tool-call-delta",
260
+ value: event.delta.partial_json ?? "",
261
+ }),
262
+ };
263
+ }
264
+ continue;
265
+ }
266
+ if (event.type === "message_stop") {
267
+ yield { delta: "", done: true };
268
+ }
269
+ }
270
+ }
271
+ catch (error) {
272
+ throw mapProviderError(error);
273
+ }
274
+ finally {
275
+ timeout.cleanup();
276
+ }
277
+ }
278
+ /**
279
+ * 调用官方 countTokens 接口做精确计数。
280
+ *
281
+ * @param messages 消息列表
282
+ * @param model 模型名
283
+ * @returns token 数
284
+ */
285
+ async countTokens(messages, model) {
286
+ const mapped = toAnthropicMessages(messages);
287
+ const payload = {
288
+ model,
289
+ messages: mapped.messages,
290
+ };
291
+ if (mapped.system) {
292
+ payload.system = mapped.system;
293
+ }
294
+ const result = await this.client.messages.countTokens(payload);
295
+ return result.input_tokens;
296
+ }
297
+ }
298
+ //# sourceMappingURL=anthropic.js.map