@zimtsui/brainswitch 0.0.15 → 0.0.17
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/README.md +32 -24
- package/build/adaptor.d.ts +1 -1
- package/build/adaptor.js +10 -6
- package/build/adaptor.js.map +1 -1
- package/build/agentloop.d.ts +1 -1
- package/build/agentloop.js +3 -3
- package/build/agentloop.js.map +1 -1
- package/build/api-types/{aliyun-stream.d.ts → aliyun.d.ts} +1 -4
- package/build/api-types/{aliyun-stream.js → aliyun.js} +6 -9
- package/build/api-types/aliyun.js.map +1 -0
- package/build/api-types/anthropic.d.ts +43 -0
- package/build/api-types/anthropic.js +288 -0
- package/build/api-types/anthropic.js.map +1 -0
- package/build/api-types/base.d.ts +3 -2
- package/build/api-types/base.js +8 -8
- package/build/api-types/base.js.map +1 -1
- package/build/api-types/google-base.d.ts +1 -0
- package/build/api-types/google-base.js +4 -1
- package/build/api-types/google-base.js.map +1 -1
- package/build/api-types/google-rest.d.ts +2 -3
- package/build/api-types/google-rest.js +10 -11
- package/build/api-types/google-rest.js.map +1 -1
- package/build/api-types/minimax.d.ts +34 -0
- package/build/api-types/minimax.js +49 -0
- package/build/api-types/minimax.js.map +1 -0
- package/build/api-types/openai-chatcompletions-base.d.ts +4 -1
- package/build/api-types/openai-chatcompletions-base.js +21 -2
- package/build/api-types/openai-chatcompletions-base.js.map +1 -1
- package/build/api-types/openai-chatcompletions-monolith-base.d.ts +2 -3
- package/build/api-types/openai-chatcompletions-monolith-base.js +19 -28
- package/build/api-types/openai-chatcompletions-monolith-base.js.map +1 -1
- package/build/api-types/openai-chatcompletions-stream-base.d.ts +4 -3
- package/build/api-types/openai-chatcompletions-stream-base.js +128 -52
- package/build/api-types/openai-chatcompletions-stream-base.js.map +1 -1
- package/build/api-types/openai-chatcompletions.d.ts +0 -3
- package/build/api-types/openai-chatcompletions.js +0 -5
- package/build/api-types/openai-chatcompletions.js.map +1 -1
- package/build/api-types/openai-responses.d.ts +4 -3
- package/build/api-types/openai-responses.js +27 -11
- package/build/api-types/openai-responses.js.map +1 -1
- package/build/api-types/openrouter-monolith.d.ts +8 -5
- package/build/api-types/openrouter-monolith.js +12 -19
- package/build/api-types/openrouter-monolith.js.map +1 -1
- package/build/api-types/openrouter-stream.d.ts +5 -6
- package/build/api-types/openrouter-stream.js +8 -15
- package/build/api-types/openrouter-stream.js.map +1 -1
- package/build/config.d.ts +4 -4
- package/build/endpoint-spec.d.ts +4 -4
- package/build/endpoint-spec.js +5 -4
- package/build/endpoint-spec.js.map +1 -1
- package/build/engine.d.ts +2 -1
- package/build/session.d.ts +2 -0
- package/build/session.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -1
- package/build/api-types/aliyun-stream.js.map +0 -1
package/README.md
CHANGED
|
@@ -8,17 +8,18 @@ Brainswitch 是一个为 AI 工作流设计的 LLM 推理 API 适配器,支持
|
|
|
8
8
|
|
|
9
9
|
## Motivation
|
|
10
10
|
|
|
11
|
-
大多数 LLM
|
|
11
|
+
大多数 LLM 的[聊天模板](https://huggingface.co/docs/transformers/en/chat_templating) ChatML 原生不支持[严格函数调用](https://platform.openai.com/docs/guides/function-calling#strict-mode),在批处理 AI 工作流中难以达到生产级可靠性。如果仅使用 OpenAI 等支持严格函数调用的服务商,那么可选的模型型号会大幅受限。
|
|
12
12
|
|
|
13
|
-
Brainswitch 支持在一次会话中途切换模型并保持对话上下文,包括 OpenAI、Google
|
|
13
|
+
Brainswitch 支持在一次会话中途切换模型并保持对话上下文,包括 OpenAI、Google、Anthropic 的深度思考模型[交替思考](https://platform.claude.com/docs/en/build-with-claude/extended-thinking#interleaved-thinking)的加密思考内容。有了 Brainswitch 就可以在会话的大量推理阶段使用最合适的模型生成自然语言结果,在最后的总结阶段切换成支持严格函数调用的模型进行结构化提交。
|
|
14
14
|
|
|
15
15
|
## 支持服务商 API 类型
|
|
16
16
|
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
17
|
+
- OpenAI Chat Completions
|
|
18
|
+
- OpenAI Responses
|
|
19
|
+
- Google
|
|
20
|
+
- 百炼
|
|
21
|
+
- OpenRouter
|
|
22
|
+
- Anthropic
|
|
22
23
|
|
|
23
24
|
## 安装
|
|
24
25
|
|
|
@@ -33,9 +34,9 @@ npm install @zimtsui/brainswitch
|
|
|
33
34
|
- `Session`:会话状态。
|
|
34
35
|
- `InferenceContext`:工作流环境,包含 [TypeLog](https://github.com/zimtsui/typelog) Logger、`AbortSignal`、用户防止并发过载的[读写锁](https://github.com/zimtsui/coroutine-locks)。
|
|
35
36
|
- `Engine`:推理引擎,从一个会话状态生成下一个会话状态。
|
|
36
|
-
- `Endpoint
|
|
37
|
+
- `Endpoint`:代表一家服务商的一个模型的 API 端点。
|
|
37
38
|
- `Adaptor`:Engine 工厂。
|
|
38
|
-
- `RoleMessage`:三类角色消息 `Developer`、`User`、`AI`,消息由 `Text
|
|
39
|
+
- `RoleMessage`:三类角色消息 `Developer`、`User`、`AI`,消息由 `Text/Function.Call/Response` 片段组成。
|
|
39
40
|
- `Function.Declaration.Map`:函数工具声明集合,使用 [JSON Schema](https://json-schema.org/) 描述函数参数。
|
|
40
41
|
|
|
41
42
|
## 配置
|
|
@@ -48,24 +49,31 @@ export type Config = {
|
|
|
48
49
|
apiKey: string;
|
|
49
50
|
model: string;
|
|
50
51
|
name: string;
|
|
51
|
-
apiType:
|
|
52
|
+
apiType:
|
|
53
|
+
| 'openai-chatcompletions'
|
|
54
|
+
| 'openai-responses'
|
|
55
|
+
| 'google'
|
|
56
|
+
| 'aliyun'
|
|
57
|
+
| 'openrouter-monolith'
|
|
58
|
+
| 'openrouter-stream'
|
|
59
|
+
| 'anthropic'
|
|
60
|
+
;
|
|
52
61
|
proxy?: string;
|
|
53
|
-
inputPrice?: number; //
|
|
54
|
-
outputPrice?: number; //
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}>;
|
|
62
|
+
inputPrice?: number; // CNY per MToken
|
|
63
|
+
outputPrice?: number; // CNY per MToken
|
|
64
|
+
cachePrice?: number; // CNY per MToken
|
|
65
|
+
rpm?: number; // Requests per minute
|
|
66
|
+
timeout?: number; // Time limit in milliseconds
|
|
67
|
+
maxTokens?: number; // Maximum number of generated tokens
|
|
68
|
+
additionalOptions?: Record<string, unknown>;
|
|
69
|
+
};
|
|
62
70
|
};
|
|
63
71
|
}
|
|
64
72
|
```
|
|
65
73
|
|
|
66
74
|
### 计费说明
|
|
67
75
|
|
|
68
|
-
|
|
76
|
+
OpenRouter 的成本会自动按服务器返回的美元成本并使用固定汇率(1 USD = 8 CNY)换算为人民币记账。
|
|
69
77
|
|
|
70
78
|
## 快速上手
|
|
71
79
|
|
|
@@ -78,7 +86,7 @@ import { RWLock } from '@zimtsui/coroutine-locks';
|
|
|
78
86
|
import { Channel } from '@zimtsui/typelog';
|
|
79
87
|
import * as Presets from '@zimtsui/typelog/presets';
|
|
80
88
|
|
|
81
|
-
//
|
|
89
|
+
// 配置推理服务商 API 接入点
|
|
82
90
|
const config: Config = {
|
|
83
91
|
brainswitch: {
|
|
84
92
|
endpoints: {
|
|
@@ -89,7 +97,7 @@ const config: Config = {
|
|
|
89
97
|
apiKey: process.env.OPENAI_API_KEY!,
|
|
90
98
|
model: 'gpt-4o-mini',
|
|
91
99
|
inputPrice: 5, outputPrice: 15, cachedPrice: 1,
|
|
92
|
-
rpm: 3000,
|
|
100
|
+
rpm: 3000, timeout: 60_000,
|
|
93
101
|
},
|
|
94
102
|
'o4-mini': {
|
|
95
103
|
name: 'o4 mini',
|
|
@@ -129,6 +137,7 @@ const fdm = {
|
|
|
129
137
|
type fdm = typeof fdm;
|
|
130
138
|
type fdu = Function.Declaration.From<fdm>;
|
|
131
139
|
|
|
140
|
+
// 实现函数工具
|
|
132
141
|
export class Submission extends Error {
|
|
133
142
|
public constructor(public weather: string, public advice: string) {
|
|
134
143
|
super(undefined);
|
|
@@ -136,7 +145,6 @@ export class Submission extends Error {
|
|
|
136
145
|
}
|
|
137
146
|
const fnm: Function.Map<fdm> = {
|
|
138
147
|
async get_weather({ city, unit }) {
|
|
139
|
-
// 实际项目中此处调用真实 API,这里仅示例
|
|
140
148
|
const data = { city, unit: unit ?? 'C', temperature: 26, sky: 'sunny' };
|
|
141
149
|
return JSON.stringify(data);
|
|
142
150
|
},
|
|
@@ -157,7 +165,7 @@ const ctx: InferenceContext = {
|
|
|
157
165
|
// 创建会话
|
|
158
166
|
const session: Session<fdu> = {
|
|
159
167
|
developerMessage: RoleMessage.Developer.create([
|
|
160
|
-
RoleMessage.Part.Text.create('
|
|
168
|
+
RoleMessage.Part.Text.create('你的工作是为用户查询天气,并给出穿衣建议。调用工具提交最终结果'),
|
|
161
169
|
]),
|
|
162
170
|
chatMessages: [
|
|
163
171
|
RoleMessage.User.create([ RoleMessage.Part.Text.create('请查询现在北京的天气,并给穿衣建议。') ]),
|
package/build/adaptor.d.ts
CHANGED
|
@@ -8,5 +8,5 @@ export declare class Adaptor {
|
|
|
8
8
|
protected constructor(config: Config);
|
|
9
9
|
private throttles;
|
|
10
10
|
getThrottle(endpointId: string): Throttle;
|
|
11
|
-
makeEngine<fdm extends Function.Declaration.Map = {}>(endpoint: string, functionDeclarationMap: fdm,
|
|
11
|
+
makeEngine<fdm extends Function.Declaration.Map = {}>(endpoint: string, functionDeclarationMap: fdm, toolChoice?: Function.ToolChoice<fdm>, parallelFunctionCall?: boolean): Engine<Function.Declaration.From<fdm>>;
|
|
12
12
|
}
|
package/build/adaptor.js
CHANGED
|
@@ -2,13 +2,14 @@ import { Config } from '#config';
|
|
|
2
2
|
import { Function } from "./function.js";
|
|
3
3
|
import {} from "./engine.js";
|
|
4
4
|
import assert from 'node:assert';
|
|
5
|
+
import { Throttle } from "./throttle.js";
|
|
5
6
|
import { OpenAIChatCompletionsEngine } from "./api-types/openai-chatcompletions.js";
|
|
6
7
|
import { GoogleRestfulEngine } from "./api-types/google-rest.js";
|
|
7
8
|
import { OpenRouterMonolithEngine } from "./api-types/openrouter-monolith.js";
|
|
8
9
|
import { OpenRouterStreamEngine } from "./api-types/openrouter-stream.js";
|
|
9
|
-
import {
|
|
10
|
+
import { AliyunEngine } from "./api-types/aliyun.js";
|
|
10
11
|
import { OpenAIResponsesEngine } from "./api-types/openai-responses.js";
|
|
11
|
-
import {
|
|
12
|
+
import { AnthropicEngine } from "./api-types/anthropic.js";
|
|
12
13
|
export class Adaptor {
|
|
13
14
|
config;
|
|
14
15
|
static create(config) {
|
|
@@ -29,14 +30,15 @@ export class Adaptor {
|
|
|
29
30
|
this.throttles.get(baseUrl).set(model, new Throttle(rpm));
|
|
30
31
|
return this.throttles.get(baseUrl).get(model);
|
|
31
32
|
}
|
|
32
|
-
makeEngine(endpoint, functionDeclarationMap,
|
|
33
|
+
makeEngine(endpoint, functionDeclarationMap, toolChoice, parallelFunctionCall) {
|
|
33
34
|
assert(endpoint in this.config.brainswitch.endpoints);
|
|
34
35
|
const endpointSpec = this.config.brainswitch.endpoints[endpoint];
|
|
35
36
|
const throttle = this.getThrottle(endpoint);
|
|
36
37
|
const options = {
|
|
37
38
|
...endpointSpec,
|
|
38
39
|
functionDeclarationMap,
|
|
39
|
-
|
|
40
|
+
toolChoice,
|
|
41
|
+
parallelFunctionCall,
|
|
40
42
|
throttle,
|
|
41
43
|
};
|
|
42
44
|
if (endpointSpec.apiType === 'openai-responses')
|
|
@@ -45,12 +47,14 @@ export class Adaptor {
|
|
|
45
47
|
return OpenAIChatCompletionsEngine.create(options);
|
|
46
48
|
else if (endpointSpec.apiType === 'google')
|
|
47
49
|
return GoogleRestfulEngine.create(options);
|
|
48
|
-
else if (endpointSpec.apiType === 'aliyun
|
|
49
|
-
return
|
|
50
|
+
else if (endpointSpec.apiType === 'aliyun')
|
|
51
|
+
return AliyunEngine.create(options);
|
|
50
52
|
else if (endpointSpec.apiType === 'openrouter-monolith')
|
|
51
53
|
return OpenRouterMonolithEngine.create(options);
|
|
52
54
|
else if (endpointSpec.apiType === 'openrouter-stream')
|
|
53
55
|
return OpenRouterStreamEngine.create(options);
|
|
56
|
+
else if (endpointSpec.apiType === 'anthropic')
|
|
57
|
+
return AnthropicEngine.create(options);
|
|
54
58
|
else
|
|
55
59
|
throw new Error();
|
|
56
60
|
}
|
package/build/adaptor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../src/adaptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAe,MAAM,aAAa,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"adaptor.js","sourceRoot":"","sources":["../src/adaptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAe,MAAM,aAAa,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAG3D,MAAM,OAAO,OAAO;IAKa;IAJtB,MAAM,CAAC,MAAM,CAAC,MAAc;QAC/B,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC;IAED,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEvC,SAAS,GAAG,IAAI,GAAG,EAAiC,CAAC;IACtD,WAAW,CAAC,UAAkB;QACjC,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAE,CAAC,OAAO,CAAC;QACvE,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAE,CAAC,KAAK,CAAC;QACnE,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAE,CAAC,GAAG,IAAI,MAAM,CAAC,iBAAiB,CAAC;QAC3F,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,GAAG,EAAoB,CAAC,CAAC;QAC7D,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,GAAG,CAAC,KAAK,CAAC;YACxC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC;IACpD,CAAC;IAEM,UAAU,CACb,QAAgB,EAChB,sBAA2B,EAC3B,UAAqC,EACrC,oBAA8B;QAE9B,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACtD,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAE,CAAC;QAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,OAAO,GAAwB;YACjC,GAAG,YAAY;YACf,sBAAsB;YACtB,UAAU;YACV,oBAAoB;YACpB,QAAQ;SACX,CAAC;QACF,IAAI,YAAY,CAAC,OAAO,KAAK,kBAAkB;YAC3C,OAAO,qBAAqB,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aACjD,IAAI,YAAY,CAAC,OAAO,KAAK,wBAAwB;YACtD,OAAO,2BAA2B,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aACvD,IAAI,YAAY,CAAC,OAAO,KAAK,QAAQ;YACtC,OAAO,mBAAmB,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aAC/C,IAAI,YAAY,CAAC,OAAO,KAAK,QAAQ;YACtC,OAAO,YAAY,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aACxC,IAAI,YAAY,CAAC,OAAO,KAAK,qBAAqB;YACnD,OAAO,wBAAwB,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aACpD,IAAI,YAAY,CAAC,OAAO,KAAK,mBAAmB;YACjD,OAAO,sBAAsB,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;aAClD,IAAI,YAAY,CAAC,OAAO,KAAK,WAAW;YACzC,OAAO,eAAe,CAAC,MAAM,CAAM,OAAO,CAAC,CAAC;;YAC3C,MAAM,IAAI,KAAK,EAAE,CAAC;IAC3B,CAAC;CACJ"}
|
package/build/agentloop.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { type Engine } from './engine.ts';
|
|
|
5
5
|
/**
|
|
6
6
|
* @param session mutable
|
|
7
7
|
*/
|
|
8
|
-
export declare function agentloop<fdm extends Function.Declaration.Map, session extends unknown = Session<Function.Declaration.From<fdm>>>(ctx: InferenceContext, session: session, engine: Engine<Function.Declaration.From<fdm>, session>,
|
|
8
|
+
export declare function agentloop<fdm extends Function.Declaration.Map, session extends unknown = Session<Function.Declaration.From<fdm>>>(ctx: InferenceContext, session: session, engine: Engine<Function.Declaration.From<fdm>, session>, fnm: Function.Map<fdm>, limit?: number): AsyncGenerator<string, string, void>;
|
|
9
9
|
export declare namespace agentloop {
|
|
10
10
|
class FunctionCallLimitExceeded extends Error {
|
|
11
11
|
}
|
package/build/agentloop.js
CHANGED
|
@@ -6,7 +6,7 @@ import assert from 'node:assert';
|
|
|
6
6
|
/**
|
|
7
7
|
* @param session mutable
|
|
8
8
|
*/
|
|
9
|
-
export async function* agentloop(ctx, session, engine,
|
|
9
|
+
export async function* agentloop(ctx, session, engine, fnm, limit = Number.POSITIVE_INFINITY) {
|
|
10
10
|
for (let i = 0; i < limit; i++) {
|
|
11
11
|
const response = await engine.stateful(ctx, session);
|
|
12
12
|
const fcs = response.getFunctionCalls();
|
|
@@ -19,13 +19,13 @@ export async function* agentloop(ctx, session, engine, functionMap, limit = Numb
|
|
|
19
19
|
}
|
|
20
20
|
else if (part instanceof Function.Call) {
|
|
21
21
|
const fc = part;
|
|
22
|
-
const f =
|
|
22
|
+
const f = fnm[fc.name];
|
|
23
23
|
assert(f);
|
|
24
24
|
pfrs.push((async () => {
|
|
25
25
|
return Function.Response.create({
|
|
26
26
|
id: fc.id,
|
|
27
27
|
name: fc.name,
|
|
28
|
-
text: await f(fc.args),
|
|
28
|
+
text: await f.call(fnm, fc.args),
|
|
29
29
|
});
|
|
30
30
|
})());
|
|
31
31
|
}
|
package/build/agentloop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agentloop.js","sourceRoot":"","sources":["../src/agentloop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAe,MAAM,aAAa,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC;;GAEG;AACH,MAAM,CAAC,KAAK,SAAU,CAAC,CAAA,SAAS,
|
|
1
|
+
{"version":3,"file":"agentloop.js","sourceRoot":"","sources":["../src/agentloop.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAgB,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAe,MAAM,aAAa,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC;;GAEG;AACH,MAAM,CAAC,KAAK,SAAU,CAAC,CAAA,SAAS,CAI5B,GAAqB,EACrB,OAAgB,EAChB,MAAuD,EACvD,GAAsB,EACtB,KAAK,GAAG,MAAM,CAAC,iBAAiB;IAGhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,MAAM;YAAE,OAAO,QAAQ,CAAC,WAAW,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAmD,EAAE,CAAC;QAChE,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC;YAChC,IAAI,IAAI,YAAY,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;gBACpD,MAAM,IAAI,CAAC,IAAI,CAAC;YACpB,CAAC;iBAAM,IAAI,IAAI,YAAY,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACvC,MAAM,EAAE,GAAG,IAAuC,CAAC;gBACnD,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACvB,MAAM,CAAC,CAAC,CAAC,CAAC;gBACV,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE;oBAClB,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAM;wBACjC,EAAE,EAAE,EAAE,CAAC,EAAE;wBACT,IAAI,EAAE,EAAE,CAAC,IAAI;wBACb,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC;qBACM,CAAC,CAAC;gBAChD,CAAC,CAAC,EAAE,CAAC,CAAC;YACV,CAAC;;gBAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QAC7B,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,CAAM,GAAG,CAAC,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,yBAAyB,CAAC,+BAA+B,CAAC,CAAC;AACnF,CAAC;AAED,WAAiB,SAAS;IACtB,MAAa,yBAA0B,SAAQ,KAAK;KAAG;IAA1C,mCAAyB,4BAAiB,CAAA;AAC3D,CAAC,EAFgB,SAAS,KAAT,SAAS,QAEzB"}
|
|
@@ -2,15 +2,12 @@ import type OpenAI from 'openai';
|
|
|
2
2
|
import { type Engine } from '../engine.ts';
|
|
3
3
|
import { Function } from '../function.ts';
|
|
4
4
|
import { OpenAIChatCompletionsStreamEngineBase } from './openai-chatcompletions-stream-base.ts';
|
|
5
|
-
|
|
6
|
-
import { type Session, type RoleMessage } from '../session.ts';
|
|
7
|
-
export declare namespace AliyunStreamEngine {
|
|
5
|
+
export declare namespace AliyunEngine {
|
|
8
6
|
interface ChatCompletionChunkChoiceDelta extends OpenAI.ChatCompletionChunk.Choice.Delta {
|
|
9
7
|
reasoning_content?: string;
|
|
10
8
|
}
|
|
11
9
|
function create<fdm extends Function.Declaration.Map = never>(options: Engine.Options<fdm>): Engine<Function.Declaration.From<fdm>>;
|
|
12
10
|
class Constructor<in out fdm extends Function.Declaration.Map = {}> extends OpenAIChatCompletionsStreamEngineBase<fdm> {
|
|
13
|
-
stateless(ctx: InferenceContext, session: Session<Function.Declaration.From<fdm>>): Promise<RoleMessage.Ai<Function.Declaration.From<fdm>>>;
|
|
14
11
|
protected getDeltaThoughts(delta: OpenAI.ChatCompletionChunk.Choice.Delta): string;
|
|
15
12
|
}
|
|
16
13
|
}
|
|
@@ -3,20 +3,17 @@ import { Function } from "../function.js";
|
|
|
3
3
|
import { OpenAIChatCompletionsStreamEngineBase } from "./openai-chatcompletions-stream-base.js";
|
|
4
4
|
import {} from "../inference-context.js";
|
|
5
5
|
import {} from "../session.js";
|
|
6
|
-
export var
|
|
7
|
-
(function (
|
|
6
|
+
export var AliyunEngine;
|
|
7
|
+
(function (AliyunEngine) {
|
|
8
8
|
function create(options) {
|
|
9
9
|
return new Constructor(options);
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
AliyunEngine.create = create;
|
|
12
12
|
class Constructor extends OpenAIChatCompletionsStreamEngineBase {
|
|
13
|
-
stateless(ctx, session) {
|
|
14
|
-
return this.stream(ctx, session);
|
|
15
|
-
}
|
|
16
13
|
getDeltaThoughts(delta) {
|
|
17
14
|
return delta.reasoning_content ?? '';
|
|
18
15
|
}
|
|
19
16
|
}
|
|
20
|
-
|
|
21
|
-
})(
|
|
22
|
-
//# sourceMappingURL=aliyun
|
|
17
|
+
AliyunEngine.Constructor = Constructor;
|
|
18
|
+
})(AliyunEngine || (AliyunEngine = {}));
|
|
19
|
+
//# sourceMappingURL=aliyun.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aliyun.js","sourceRoot":"","sources":["../../src/api-types/aliyun.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,qCAAqC,EAAE,MAAM,yCAAyC,CAAC;AAChG,OAAO,EAAyB,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAkC,MAAM,eAAe,CAAC;AAI/D,MAAM,KAAW,YAAY,CAc5B;AAdD,WAAiB,YAAY;IAK5B,SAAgB,MAAM,CAA+C,OAA4B;QAChG,OAAO,IAAI,WAAW,CAAM,OAAO,CAAC,CAAC;IACtC,CAAC;IAFe,mBAAM,SAErB,CAAA;IAED,MAAa,WAA8D,SAAQ,qCAA0C;QAClH,gBAAgB,CAAC,KAA8C;YACxE,OAAQ,KAAqD,CAAC,iBAAiB,IAAI,EAAE,CAAC;QACvF,CAAC;KACD;IAJY,wBAAW,cAIvB,CAAA;AACF,CAAC,EAdgB,YAAY,KAAZ,YAAY,QAc5B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { EngineBase } from './base.ts';
|
|
2
|
+
import { Function } from '../function.ts';
|
|
3
|
+
import { RoleMessage, type ChatMessage, type Session } from '../session.ts';
|
|
4
|
+
import { type Engine } from '../engine.ts';
|
|
5
|
+
import { type InferenceContext } from '../inference-context.ts';
|
|
6
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
7
|
+
export declare namespace AnthropicEngine {
|
|
8
|
+
function create<fdm extends Function.Declaration.Map = {}>(options: Engine.Options<fdm>): Engine<Function.Declaration.From<fdm>>;
|
|
9
|
+
class Constructor<in out fdm extends Function.Declaration.Map = {}> extends EngineBase<fdm> {
|
|
10
|
+
protected anthropic: Anthropic;
|
|
11
|
+
protected parallel: boolean;
|
|
12
|
+
constructor(options: Engine.Options<fdm>);
|
|
13
|
+
protected convertFromFunctionCall(fc: Function.Call.Distributive<Function.Declaration.From<fdm>>): Anthropic.ToolUseBlock;
|
|
14
|
+
protected convertToFunctionCall(apifc: Anthropic.ToolUseBlock): Function.Call.Distributive<Function.Declaration.From<fdm>>;
|
|
15
|
+
protected convertFromFunctionResponse(fr: Function.Response.Distributive<Function.Declaration.From<fdm>>): Anthropic.ToolResultBlockParam;
|
|
16
|
+
protected convertFromUserMessage(userMessage: RoleMessage.User<Function.Declaration.From<fdm>>): Anthropic.ContentBlockParam[];
|
|
17
|
+
protected convertFromAiMessage(aiMessage: RoleMessage.Ai<Function.Declaration.From<fdm>>): Anthropic.ContentBlockParam[];
|
|
18
|
+
protected convertFromChatMessage(chatMessage: ChatMessage<Function.Declaration.From<fdm>>): Anthropic.MessageParam;
|
|
19
|
+
protected convertFromFunctionDeclarationEntry(fdentry: Function.Declaration.Entry.From<fdm>): Anthropic.Tool;
|
|
20
|
+
protected convertFromToolChoice(toolChoice: Function.ToolChoice<fdm>, parallel: boolean): Anthropic.ToolChoice;
|
|
21
|
+
protected makeParams(session: Session<Function.Declaration.From<fdm>>): Anthropic.MessageCreateParamsStreaming;
|
|
22
|
+
protected convertToAiMessage(raw: Anthropic.ContentBlock[]): AnthropicAiMessage<Function.Declaration.From<fdm>>;
|
|
23
|
+
protected validateFunctionCallByToolChoice(functionCalls: Function.Call.Distributive<Function.Declaration.From<fdm>>[]): void;
|
|
24
|
+
protected calcCost(usage: Anthropic.Usage): number;
|
|
25
|
+
stateless(ctx: InferenceContext, session: Session<Function.Declaration.From<fdm>>, retry?: number): Promise<RoleMessage.Ai<Function.Declaration.From<fdm>>>;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export type AnthropicAiMessage<fdu extends Function.Declaration> = AnthropicAiMessage.Constructor<fdu>;
|
|
29
|
+
export declare namespace AnthropicAiMessage {
|
|
30
|
+
function create<fdu extends Function.Declaration>(parts: RoleMessage.Ai.Part<fdu>[], raw: Anthropic.ContentBlock[]): AnthropicAiMessage<fdu>;
|
|
31
|
+
const NOMINAL: unique symbol;
|
|
32
|
+
class Constructor<out fdu extends Function.Declaration> extends RoleMessage.Ai.Constructor<fdu> {
|
|
33
|
+
raw: Anthropic.ContentBlock[];
|
|
34
|
+
readonly [NOMINAL]: void;
|
|
35
|
+
constructor(parts: RoleMessage.Ai.Part<fdu>[], raw: Anthropic.ContentBlock[]);
|
|
36
|
+
}
|
|
37
|
+
interface Snapshot<in out fdu extends Function.Declaration = never> {
|
|
38
|
+
parts: RoleMessage.Ai.Part.Snapshot<fdu>[];
|
|
39
|
+
raw: Anthropic.ContentBlock[];
|
|
40
|
+
}
|
|
41
|
+
function restore<fdu extends Function.Declaration>(snapshot: Snapshot<fdu>): AnthropicAiMessage<fdu>;
|
|
42
|
+
function capture<fdu extends Function.Declaration>(message: AnthropicAiMessage<fdu>): Snapshot<fdu>;
|
|
43
|
+
}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { EngineBase } from "./base.js";
|
|
2
|
+
import { Function } from "../function.js";
|
|
3
|
+
import { RoleMessage } from "../session.js";
|
|
4
|
+
import {} from "../engine.js";
|
|
5
|
+
import {} from "../inference-context.js";
|
|
6
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
7
|
+
import assert from 'node:assert';
|
|
8
|
+
import { TransientError } from "./base.js";
|
|
9
|
+
import Ajv from 'ajv';
|
|
10
|
+
import {} from '@sinclair/typebox';
|
|
11
|
+
const ajv = new Ajv();
|
|
12
|
+
export var AnthropicEngine;
|
|
13
|
+
(function (AnthropicEngine) {
|
|
14
|
+
function create(options) {
|
|
15
|
+
return new Constructor(options);
|
|
16
|
+
}
|
|
17
|
+
AnthropicEngine.create = create;
|
|
18
|
+
class Constructor extends EngineBase {
|
|
19
|
+
anthropic = new Anthropic({
|
|
20
|
+
baseURL: this.baseUrl,
|
|
21
|
+
apiKey: this.apiKey,
|
|
22
|
+
fetchOptions: { dispatcher: this.proxyAgent },
|
|
23
|
+
});
|
|
24
|
+
parallel;
|
|
25
|
+
constructor(options) {
|
|
26
|
+
super(options);
|
|
27
|
+
this.parallel = options.parallelFunctionCall ?? false;
|
|
28
|
+
}
|
|
29
|
+
convertFromFunctionCall(fc) {
|
|
30
|
+
assert(fc.id);
|
|
31
|
+
return {
|
|
32
|
+
type: 'tool_use',
|
|
33
|
+
id: fc.id,
|
|
34
|
+
name: fc.name,
|
|
35
|
+
input: fc.args,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
convertToFunctionCall(apifc) {
|
|
39
|
+
const fditem = this.fdm[apifc.name];
|
|
40
|
+
assert(fditem, new TransientError('Invalid function call', { cause: apifc }));
|
|
41
|
+
assert(ajv.validate(fditem.paraschema, apifc.input), new TransientError('Invalid function call', { cause: apifc }));
|
|
42
|
+
return Function.Call.create({
|
|
43
|
+
id: apifc.id,
|
|
44
|
+
name: apifc.name,
|
|
45
|
+
args: apifc.input,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
convertFromFunctionResponse(fr) {
|
|
49
|
+
assert(fr.id);
|
|
50
|
+
return {
|
|
51
|
+
type: 'tool_result',
|
|
52
|
+
tool_use_id: fr.id,
|
|
53
|
+
content: fr.text,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
convertFromUserMessage(userMessage) {
|
|
57
|
+
return userMessage.parts.map(part => {
|
|
58
|
+
if (part instanceof RoleMessage.Part.Text.Constructor)
|
|
59
|
+
return {
|
|
60
|
+
type: 'text',
|
|
61
|
+
text: part.text,
|
|
62
|
+
};
|
|
63
|
+
else if (part instanceof Function.Response)
|
|
64
|
+
return this.convertFromFunctionResponse(part);
|
|
65
|
+
else
|
|
66
|
+
throw new Error();
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
convertFromAiMessage(aiMessage) {
|
|
70
|
+
if (aiMessage instanceof AnthropicAiMessage.Constructor)
|
|
71
|
+
return aiMessage.raw;
|
|
72
|
+
else {
|
|
73
|
+
return aiMessage.parts.map(part => {
|
|
74
|
+
if (part instanceof RoleMessage.Part.Text.Constructor)
|
|
75
|
+
return {
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: part.text,
|
|
78
|
+
};
|
|
79
|
+
else if (part instanceof Function.Call)
|
|
80
|
+
return this.convertFromFunctionCall(part);
|
|
81
|
+
else
|
|
82
|
+
throw new Error();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
convertFromChatMessage(chatMessage) {
|
|
87
|
+
if (chatMessage instanceof RoleMessage.User.Constructor)
|
|
88
|
+
return { role: 'user', content: this.convertFromUserMessage(chatMessage) };
|
|
89
|
+
else if (chatMessage instanceof RoleMessage.Ai.Constructor)
|
|
90
|
+
return { role: 'assistant', content: this.convertFromAiMessage(chatMessage) };
|
|
91
|
+
else
|
|
92
|
+
throw new Error();
|
|
93
|
+
}
|
|
94
|
+
convertFromFunctionDeclarationEntry(fdentry) {
|
|
95
|
+
return {
|
|
96
|
+
name: fdentry[0],
|
|
97
|
+
description: fdentry[1].description,
|
|
98
|
+
input_schema: fdentry[1].paraschema,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
convertFromToolChoice(toolChoice, parallel) {
|
|
102
|
+
if (toolChoice === Function.ToolChoice.NONE)
|
|
103
|
+
return { type: 'none' };
|
|
104
|
+
else if (toolChoice === Function.ToolChoice.REQUIRED)
|
|
105
|
+
return { type: 'any', disable_parallel_tool_use: !parallel };
|
|
106
|
+
else if (toolChoice === Function.ToolChoice.AUTO)
|
|
107
|
+
return { type: 'auto', disable_parallel_tool_use: !parallel };
|
|
108
|
+
else {
|
|
109
|
+
assert(toolChoice.length === 1);
|
|
110
|
+
return { type: 'tool', name: toolChoice[0], disable_parallel_tool_use: !parallel };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
makeParams(session) {
|
|
114
|
+
return {
|
|
115
|
+
model: this.model,
|
|
116
|
+
stream: true,
|
|
117
|
+
messages: session.chatMessages.map(chatMessage => this.convertFromChatMessage(chatMessage)),
|
|
118
|
+
system: session.developerMessage?.parts.map(part => ({ type: 'text', text: part.text })),
|
|
119
|
+
tools: Object.keys(this.fdm).length
|
|
120
|
+
? Object.entries(this.fdm).map(fdentry => this.convertFromFunctionDeclarationEntry(fdentry)) : undefined,
|
|
121
|
+
max_tokens: this.tokenLimit ?? 64 * 1024,
|
|
122
|
+
...this.additionalOptions,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
convertToAiMessage(raw) {
|
|
126
|
+
const parts = raw.flatMap((item) => {
|
|
127
|
+
if (item.type === 'text') {
|
|
128
|
+
return [RoleMessage.Part.Text.create(item.text)];
|
|
129
|
+
}
|
|
130
|
+
else if (item.type === 'tool_use')
|
|
131
|
+
return [this.convertToFunctionCall(item)];
|
|
132
|
+
else if (item.type === 'thinking')
|
|
133
|
+
return [];
|
|
134
|
+
else
|
|
135
|
+
throw new Error();
|
|
136
|
+
});
|
|
137
|
+
return AnthropicAiMessage.create(parts, raw);
|
|
138
|
+
}
|
|
139
|
+
validateFunctionCallByToolChoice(functionCalls) {
|
|
140
|
+
if (this.toolChoice === Function.ToolChoice.REQUIRED)
|
|
141
|
+
assert(functionCalls.length, new TransientError());
|
|
142
|
+
else if (this.toolChoice instanceof Array)
|
|
143
|
+
for (const fc of functionCalls)
|
|
144
|
+
assert(this.toolChoice.includes(fc.name), new TransientError());
|
|
145
|
+
else if (this.toolChoice === Function.ToolChoice.NONE)
|
|
146
|
+
assert(!functionCalls.length, new TransientError());
|
|
147
|
+
}
|
|
148
|
+
calcCost(usage) {
|
|
149
|
+
const cacheHitTokenCount = usage.cache_read_input_tokens || 0;
|
|
150
|
+
const cacheMissTokenCount = usage.input_tokens - cacheHitTokenCount;
|
|
151
|
+
return this.inputPrice * cacheMissTokenCount / 1e6 +
|
|
152
|
+
this.cachedPrice * cacheHitTokenCount / 1e6 +
|
|
153
|
+
this.outputPrice * usage.output_tokens / 1e6;
|
|
154
|
+
}
|
|
155
|
+
async stateless(ctx, session, retry = 0) {
|
|
156
|
+
const signalTimeout = this.timeout ? AbortSignal.timeout(this.timeout) : undefined;
|
|
157
|
+
const signal = ctx.signal && signalTimeout ? AbortSignal.any([
|
|
158
|
+
ctx.signal,
|
|
159
|
+
signalTimeout,
|
|
160
|
+
]) : ctx.signal || signalTimeout;
|
|
161
|
+
try {
|
|
162
|
+
const params = this.makeParams(session);
|
|
163
|
+
ctx.logger.message?.trace(params);
|
|
164
|
+
await this.throttle.requests(ctx);
|
|
165
|
+
const stream = this.anthropic.messages.stream(params, { signal });
|
|
166
|
+
let response = null;
|
|
167
|
+
for await (const event of stream) {
|
|
168
|
+
if (event.type === 'message_start') {
|
|
169
|
+
ctx.logger.message?.trace(event);
|
|
170
|
+
response = structuredClone(event.message);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
assert(response);
|
|
174
|
+
if (event.type === 'message_delta') {
|
|
175
|
+
ctx.logger.message?.trace(event);
|
|
176
|
+
response.stop_sequence = event.delta.stop_sequence ?? response.stop_sequence;
|
|
177
|
+
response.stop_reason = event.delta.stop_reason ?? response.stop_reason;
|
|
178
|
+
}
|
|
179
|
+
else if (event.type === 'message_stop') {
|
|
180
|
+
ctx.logger.message?.trace(event);
|
|
181
|
+
}
|
|
182
|
+
else if (event.type === 'content_block_start') {
|
|
183
|
+
ctx.logger.message?.trace(event);
|
|
184
|
+
const contentBlock = structuredClone(event.content_block);
|
|
185
|
+
response.content.push(contentBlock);
|
|
186
|
+
if (contentBlock.type === 'tool_use')
|
|
187
|
+
contentBlock.input = '';
|
|
188
|
+
}
|
|
189
|
+
else if (event.type === 'content_block_delta') {
|
|
190
|
+
const contentBlock = response.content[event.index];
|
|
191
|
+
if (event.delta.type === 'text_delta') {
|
|
192
|
+
ctx.logger.inference?.debug(event.delta.text);
|
|
193
|
+
assert(contentBlock?.type === 'text');
|
|
194
|
+
contentBlock.text += event.delta.text;
|
|
195
|
+
}
|
|
196
|
+
else if (event.delta.type === 'thinking_delta') {
|
|
197
|
+
ctx.logger.inference?.trace(event.delta.thinking);
|
|
198
|
+
assert(contentBlock?.type === 'thinking');
|
|
199
|
+
contentBlock.thinking += event.delta.thinking;
|
|
200
|
+
}
|
|
201
|
+
else if (event.delta.type === 'signature_delta') {
|
|
202
|
+
assert(contentBlock?.type === 'thinking');
|
|
203
|
+
contentBlock.signature += event.delta.signature;
|
|
204
|
+
}
|
|
205
|
+
else if (event.delta.type === 'input_json_delta') {
|
|
206
|
+
ctx.logger.inference?.debug(event.delta.partial_json);
|
|
207
|
+
assert(contentBlock?.type === 'tool_use');
|
|
208
|
+
assert(typeof contentBlock.input === 'string');
|
|
209
|
+
contentBlock.input += event.delta.partial_json;
|
|
210
|
+
}
|
|
211
|
+
else
|
|
212
|
+
throw new Error('Unknown type of content block delta', { cause: event.delta });
|
|
213
|
+
}
|
|
214
|
+
else if (event.type === 'content_block_stop') {
|
|
215
|
+
const contentBlock = response.content[event.index];
|
|
216
|
+
if (contentBlock?.type === 'text')
|
|
217
|
+
ctx.logger.inference?.debug('\n');
|
|
218
|
+
else if (contentBlock?.type === 'thinking')
|
|
219
|
+
ctx.logger.inference?.trace('\n');
|
|
220
|
+
else if (contentBlock?.type === 'tool_use')
|
|
221
|
+
ctx.logger.inference?.debug('\n');
|
|
222
|
+
ctx.logger.message?.trace(event);
|
|
223
|
+
if (contentBlock?.type === 'tool_use') {
|
|
224
|
+
assert(typeof contentBlock.input === 'string');
|
|
225
|
+
contentBlock.input = JSON.parse(contentBlock.input);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else
|
|
229
|
+
throw new Error('Unknown stream event', { cause: event });
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
assert(response);
|
|
233
|
+
if (response.stop_reason === 'max_tokens')
|
|
234
|
+
throw new TransientError('Token limit exceeded.', { cause: response });
|
|
235
|
+
assert(response.stop_reason === 'end_turn' || response.stop_reason === 'tool_use', new TransientError('Abnormal stop reason', { cause: response }));
|
|
236
|
+
const cost = this.calcCost(response.usage);
|
|
237
|
+
ctx.logger.cost?.(cost);
|
|
238
|
+
ctx.logger.message?.debug(response.usage);
|
|
239
|
+
const aiMessage = this.convertToAiMessage(response.content);
|
|
240
|
+
this.validateFunctionCallByToolChoice(aiMessage.getFunctionCalls());
|
|
241
|
+
return aiMessage;
|
|
242
|
+
}
|
|
243
|
+
catch (e) {
|
|
244
|
+
if (ctx.signal?.aborted)
|
|
245
|
+
throw e;
|
|
246
|
+
else if (signalTimeout?.aborted) { } // 推理超时
|
|
247
|
+
else if (e instanceof TransientError) { } // 模型抽风
|
|
248
|
+
else if (e instanceof TypeError) { } // 网络故障
|
|
249
|
+
else
|
|
250
|
+
throw e;
|
|
251
|
+
ctx.logger.message?.warn(e);
|
|
252
|
+
if (retry < 3)
|
|
253
|
+
return await this.stateless(ctx, session, retry + 1);
|
|
254
|
+
else
|
|
255
|
+
throw e;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
AnthropicEngine.Constructor = Constructor;
|
|
260
|
+
})(AnthropicEngine || (AnthropicEngine = {}));
|
|
261
|
+
export var AnthropicAiMessage;
|
|
262
|
+
(function (AnthropicAiMessage) {
|
|
263
|
+
function create(parts, raw) {
|
|
264
|
+
return new Constructor(parts, raw);
|
|
265
|
+
}
|
|
266
|
+
AnthropicAiMessage.create = create;
|
|
267
|
+
AnthropicAiMessage.NOMINAL = Symbol();
|
|
268
|
+
class Constructor extends RoleMessage.Ai.Constructor {
|
|
269
|
+
raw;
|
|
270
|
+
constructor(parts, raw) {
|
|
271
|
+
super(parts);
|
|
272
|
+
this.raw = raw;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
AnthropicAiMessage.Constructor = Constructor;
|
|
276
|
+
function restore(snapshot) {
|
|
277
|
+
return new Constructor(RoleMessage.Ai.restore(snapshot.parts).parts, snapshot.raw);
|
|
278
|
+
}
|
|
279
|
+
AnthropicAiMessage.restore = restore;
|
|
280
|
+
function capture(message) {
|
|
281
|
+
return {
|
|
282
|
+
parts: RoleMessage.Ai.capture(message),
|
|
283
|
+
raw: message.raw,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
AnthropicAiMessage.capture = capture;
|
|
287
|
+
})(AnthropicAiMessage || (AnthropicAiMessage = {}));
|
|
288
|
+
//# sourceMappingURL=anthropic.js.map
|