@polka-codes/core 0.0.4 → 0.1.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.
- package/README.md +69 -0
- package/dist/Agent/AgentBase.d.ts +49 -0
- package/dist/Agent/AgentBase.js +158 -0
- package/dist/Agent/AgentBase.js.map +1 -0
- package/dist/Agent/CoderAgent/index.d.ts +17 -0
- package/dist/Agent/CoderAgent/index.js +32 -0
- package/dist/Agent/CoderAgent/index.js.map +1 -0
- package/dist/Agent/CoderAgent/prompts.d.ts +20 -0
- package/dist/Agent/CoderAgent/prompts.js +165 -0
- package/dist/Agent/CoderAgent/prompts.js.map +1 -0
- package/dist/Agent/CoderAgent/prompts.test.d.ts +1 -0
- package/dist/Agent/CoderAgent/prompts.test.js +20 -0
- package/dist/Agent/CoderAgent/prompts.test.js.map +1 -0
- package/dist/Agent/index.d.ts +2 -0
- package/dist/Agent/index.js +3 -0
- package/dist/Agent/index.js.map +1 -0
- package/dist/Agent/parseAssistantMessage.d.ts +45 -0
- package/dist/Agent/parseAssistantMessage.js +103 -0
- package/dist/Agent/parseAssistantMessage.js.map +1 -0
- package/dist/Agent/parseAssistantMessage.test.d.ts +1 -0
- package/dist/Agent/parseAssistantMessage.test.js +172 -0
- package/dist/Agent/parseAssistantMessage.test.js.map +1 -0
- package/dist/Agent/prompts.d.ts +7 -0
- package/dist/Agent/prompts.js +93 -0
- package/dist/Agent/prompts.js.map +1 -0
- package/dist/AiService/AiServiceBase.d.ts +29 -0
- package/dist/AiService/AiServiceBase.js +3 -0
- package/dist/AiService/AiServiceBase.js.map +1 -0
- package/dist/AiService/AnthropicService.d.ts +11 -0
- package/dist/AiService/AnthropicService.js +185 -0
- package/dist/AiService/AnthropicService.js.map +1 -0
- package/dist/AiService/DeepSeekService.d.ts +11 -0
- package/dist/AiService/DeepSeekService.js +64 -0
- package/dist/AiService/DeepSeekService.js.map +1 -0
- package/dist/AiService/ModelInfo.d.ts +79 -0
- package/dist/AiService/ModelInfo.js +67 -0
- package/dist/AiService/ModelInfo.js.map +1 -0
- package/dist/AiService/OllamaService.d.ts +11 -0
- package/dist/AiService/OllamaService.js +47 -0
- package/dist/AiService/OllamaService.js.map +1 -0
- package/dist/AiService/index.d.ts +12 -0
- package/dist/AiService/index.js +20 -0
- package/dist/AiService/index.js.map +1 -0
- package/dist/AiService/utils.d.ts +4 -0
- package/dist/AiService/utils.js +187 -0
- package/dist/AiService/utils.js.map +1 -0
- package/dist/AiService/utils.test.d.ts +1 -0
- package/dist/AiService/utils.test.js +275 -0
- package/dist/AiService/utils.test.js.map +1 -0
- package/dist/index.d.ts +4 -10
- package/dist/index.js +4 -10
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +5 -0
- package/dist/logger.js +25 -0
- package/dist/logger.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/tools.d.ts +200 -0
- package/dist/tools/tools.js +329 -0
- package/dist/tools/tools.js.map +1 -0
- package/dist/tools/types.d.ts +49 -0
- package/dist/tools/types.js +9 -0
- package/dist/tools/types.js.map +1 -0
- package/package.json +9 -2
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse an assistant's message into an array of text content and tool use content.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* const tools = [
|
|
6
|
+
* {
|
|
7
|
+
* name: "search",
|
|
8
|
+
* parameters: [
|
|
9
|
+
* {name: "query", type: "string"}
|
|
10
|
+
* ]
|
|
11
|
+
* }
|
|
12
|
+
* ]
|
|
13
|
+
*
|
|
14
|
+
* // Text only
|
|
15
|
+
* parseAssistantMessage("Hello world", tools, "tool_")
|
|
16
|
+
* // Returns: [{type: "text", content: "Hello world"}]
|
|
17
|
+
*
|
|
18
|
+
* // Tool use with parameters
|
|
19
|
+
* parseAssistantMessage(
|
|
20
|
+
* `Let me search that for you
|
|
21
|
+
* <tool_search>
|
|
22
|
+
* <tool_parameter_query>cats</tool_parameter_query>
|
|
23
|
+
* </tool_search>
|
|
24
|
+
* Here are the results`,
|
|
25
|
+
* tools,
|
|
26
|
+
* "tool_"
|
|
27
|
+
* )
|
|
28
|
+
* // Returns: [
|
|
29
|
+
* // {type: "text", content: "Let me search that for you"},
|
|
30
|
+
* // {type: "tool_use", name: "search", params: {query: "cats"}},
|
|
31
|
+
* // {type: "text", content: "Here are the results"}
|
|
32
|
+
* // ]
|
|
33
|
+
*/
|
|
34
|
+
export function parseAssistantMessage(assistantMessage, tools, toolNamePrefix) {
|
|
35
|
+
const parameterPrefix = `${toolNamePrefix}parameter_`;
|
|
36
|
+
const results = [];
|
|
37
|
+
// Generate list of possible tool tags
|
|
38
|
+
const toolTags = tools.map((tool) => `${toolNamePrefix}${tool.name}`);
|
|
39
|
+
const toolPattern = toolTags.join('|');
|
|
40
|
+
// Find the outermost tool tag by matching first opening and last closing tags
|
|
41
|
+
const tagRegex = new RegExp(`<(${toolPattern})>(.*)<\\/\\1>`, 's');
|
|
42
|
+
const match = assistantMessage.match(tagRegex);
|
|
43
|
+
if (match) {
|
|
44
|
+
// Split message into parts
|
|
45
|
+
const beforeTag = assistantMessage.slice(0, match.index).trim();
|
|
46
|
+
const fullTagContent = match[0];
|
|
47
|
+
// Add text before tag if exists
|
|
48
|
+
if (beforeTag) {
|
|
49
|
+
results.push({
|
|
50
|
+
type: 'text',
|
|
51
|
+
content: beforeTag,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
// Find which tool was used
|
|
55
|
+
const tagName = match[1];
|
|
56
|
+
const toolName = tagName.replace(toolNamePrefix, '');
|
|
57
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
58
|
+
if (tool) {
|
|
59
|
+
// Parse parameters using new XML-like syntax
|
|
60
|
+
const params = {};
|
|
61
|
+
// Extract parameters while preserving nested content
|
|
62
|
+
for (const param of tool.parameters) {
|
|
63
|
+
const paramName = `${parameterPrefix}${param.name}`;
|
|
64
|
+
const escapedParamName = paramName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
65
|
+
// Match parameter content non-greedily while preserving nested content
|
|
66
|
+
const paramPattern = `<${escapedParamName}>([\\s\\S]*?)<\\/${escapedParamName}>`;
|
|
67
|
+
const paramMatch = fullTagContent.match(new RegExp(paramPattern, 's'));
|
|
68
|
+
if (paramMatch) {
|
|
69
|
+
params[param.name] = paramMatch[1].trim();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
results.push({
|
|
73
|
+
type: 'tool_use',
|
|
74
|
+
name: toolName,
|
|
75
|
+
params,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
// Unknown tool - treat as text
|
|
80
|
+
results.push({
|
|
81
|
+
type: 'text',
|
|
82
|
+
content: fullTagContent,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// Add text after the full tag if exists
|
|
86
|
+
const afterTag = assistantMessage.slice((match.index ?? 0) + fullTagContent.length).trim();
|
|
87
|
+
if (afterTag) {
|
|
88
|
+
results.push({
|
|
89
|
+
type: 'text',
|
|
90
|
+
content: afterTag,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// No tool tags found, treat entire message as text
|
|
96
|
+
results.push({
|
|
97
|
+
type: 'text',
|
|
98
|
+
content: assistantMessage,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return results;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=parseAssistantMessage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseAssistantMessage.js","sourceRoot":"","sources":["../../src/Agent/parseAssistantMessage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
import { parseAssistantMessage } from './parseAssistantMessage';
|
|
3
|
+
describe('parseAssistantMessage', () => {
|
|
4
|
+
const mockTools = [
|
|
5
|
+
{
|
|
6
|
+
name: 'test_tool',
|
|
7
|
+
description: 'A test tool',
|
|
8
|
+
parameters: [
|
|
9
|
+
{ name: 'param1', description: 'First parameter', required: true, usageValue: 'value1' },
|
|
10
|
+
{ name: 'param2', description: 'Second parameter', required: false, usageValue: 'value2' },
|
|
11
|
+
],
|
|
12
|
+
},
|
|
13
|
+
];
|
|
14
|
+
const toolPrefix = 'tool_';
|
|
15
|
+
test('should parse plain text message', () => {
|
|
16
|
+
const message = 'This is a plain text message';
|
|
17
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
18
|
+
expect(result).toEqual([
|
|
19
|
+
{
|
|
20
|
+
type: 'text',
|
|
21
|
+
content: message,
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
25
|
+
test('should parse message with tool use and XML-like parameters', () => {
|
|
26
|
+
const message = `<tool_test_tool>
|
|
27
|
+
<tool_parameter_param1>value1</tool_parameter_param1>
|
|
28
|
+
<tool_parameter_param2>value2</tool_parameter_param2>
|
|
29
|
+
</tool_test_tool>`;
|
|
30
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
31
|
+
expect(result).toEqual([
|
|
32
|
+
{
|
|
33
|
+
type: 'tool_use',
|
|
34
|
+
name: 'test_tool',
|
|
35
|
+
params: {
|
|
36
|
+
param1: 'value1',
|
|
37
|
+
param2: 'value2',
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
});
|
|
42
|
+
test('should parse message with text before and after tool use', () => {
|
|
43
|
+
const message = `Before text <tool_test_tool>
|
|
44
|
+
<tool_parameter_param1>value1</tool_parameter_param1>
|
|
45
|
+
</tool_test_tool> After text`;
|
|
46
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
47
|
+
expect(result).toEqual([
|
|
48
|
+
{
|
|
49
|
+
type: 'text',
|
|
50
|
+
content: 'Before text',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
type: 'tool_use',
|
|
54
|
+
name: 'test_tool',
|
|
55
|
+
params: {
|
|
56
|
+
param1: 'value1',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: 'text',
|
|
61
|
+
content: 'After text',
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
});
|
|
65
|
+
test('should handle tool with missing optional parameter', () => {
|
|
66
|
+
const message = `<tool_test_tool>
|
|
67
|
+
<tool_parameter_param1>value1</tool_parameter_param1>
|
|
68
|
+
</tool_test_tool>`;
|
|
69
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
70
|
+
expect(result).toEqual([
|
|
71
|
+
{
|
|
72
|
+
type: 'tool_use',
|
|
73
|
+
name: 'test_tool',
|
|
74
|
+
params: {
|
|
75
|
+
param1: 'value1',
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
});
|
|
80
|
+
test('should handle message with unknown tool', () => {
|
|
81
|
+
const message = `<tool_unknown>
|
|
82
|
+
<tool_parameter_param1>value1</tool_parameter_param1>
|
|
83
|
+
</tool_unknown>`;
|
|
84
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
85
|
+
// Should treat the entire message as text since tool is unknown
|
|
86
|
+
expect(result).toEqual([
|
|
87
|
+
{
|
|
88
|
+
type: 'text',
|
|
89
|
+
content: message,
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
});
|
|
93
|
+
test('should handle message with malformed parameter tags', () => {
|
|
94
|
+
const message = '<tool_test_tool>malformed params</tool_test_tool>';
|
|
95
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
96
|
+
expect(result).toEqual([
|
|
97
|
+
{
|
|
98
|
+
type: 'tool_use',
|
|
99
|
+
name: 'test_tool',
|
|
100
|
+
params: {}, // No params should be parsed
|
|
101
|
+
},
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
test('should handle multiline parameter values', () => {
|
|
105
|
+
const message = `<tool_test_tool>
|
|
106
|
+
<tool_parameter_param1>
|
|
107
|
+
multiline
|
|
108
|
+
value
|
|
109
|
+
</tool_parameter_param1>
|
|
110
|
+
</tool_test_tool>`;
|
|
111
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
112
|
+
expect(result).toEqual([
|
|
113
|
+
{
|
|
114
|
+
type: 'tool_use',
|
|
115
|
+
name: 'test_tool',
|
|
116
|
+
params: {
|
|
117
|
+
param1: 'multiline\n value',
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
]);
|
|
121
|
+
});
|
|
122
|
+
test('should handle parameter values containing XML-like tags', () => {
|
|
123
|
+
const message = `<tool_test_tool>
|
|
124
|
+
<tool_parameter_param1>value with <some>xml</some> tags</tool_parameter_param1>
|
|
125
|
+
<tool_parameter_param2>another <tag>nested</tag> value</tool_parameter_param2>
|
|
126
|
+
</tool_test_tool>`;
|
|
127
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
128
|
+
expect(result).toEqual([
|
|
129
|
+
{
|
|
130
|
+
type: 'tool_use',
|
|
131
|
+
name: 'test_tool',
|
|
132
|
+
params: {
|
|
133
|
+
param1: 'value with <some>xml</some> tags',
|
|
134
|
+
param2: 'another <tag>nested</tag> value',
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
});
|
|
139
|
+
test('should handle parameter values containing incomplete/malformed XML tags', () => {
|
|
140
|
+
const message = `<tool_test_tool>
|
|
141
|
+
<tool_parameter_param1>value with <unclosed tag</tool_parameter_param1>
|
|
142
|
+
<tool_parameter_param2>value with </>empty tag</> here</tool_parameter_param2>
|
|
143
|
+
</tool_test_tool>`;
|
|
144
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
145
|
+
expect(result).toEqual([
|
|
146
|
+
{
|
|
147
|
+
type: 'tool_use',
|
|
148
|
+
name: 'test_tool',
|
|
149
|
+
params: {
|
|
150
|
+
param1: 'value with <unclosed tag',
|
|
151
|
+
param2: 'value with </>empty tag</> here',
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
test('should handle parameter values containing tool-like tags', () => {
|
|
157
|
+
const message = `<tool_test_tool>
|
|
158
|
+
<tool_parameter_param1>value with <tool_test_tool>nested tool</tool_test_tool> tags</tool_parameter_param1>
|
|
159
|
+
</tool_test_tool>`;
|
|
160
|
+
const result = parseAssistantMessage(message, mockTools, toolPrefix);
|
|
161
|
+
expect(result).toEqual([
|
|
162
|
+
{
|
|
163
|
+
type: 'tool_use',
|
|
164
|
+
name: 'test_tool',
|
|
165
|
+
params: {
|
|
166
|
+
param1: 'value with <tool_test_tool>nested tool</tool_test_tool> tags',
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
]);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
//# sourceMappingURL=parseAssistantMessage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseAssistantMessage.test.js","sourceRoot":"","sources":["../../src/Agent/parseAssistantMessage.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAEjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAE/D,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,MAAM,SAAS,GAAe;QAC5B;YACE,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,aAAa;YAC1B,UAAU,EAAE;gBACV,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE;gBACxF,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kBAAkB,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE;aAC3F;SACF;KACF,CAAA;IACD,MAAM,UAAU,GAAG,OAAO,CAAA;IAE1B,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC3C,MAAM,OAAO,GAAG,8BAA8B,CAAA;QAC9C,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,OAAO;aACjB;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACtE,MAAM,OAAO,GAAG;;;sBAGE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,QAAQ;oBAChB,MAAM,EAAE,QAAQ;iBACjB;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;QACpE,MAAM,OAAO,GAAG;;iCAEa,CAAA;QAC7B,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,aAAa;aACvB;YACD;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,QAAQ;iBACjB;aACF;YACD;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,YAAY;aACtB;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC9D,MAAM,OAAO,GAAG;;sBAEE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,QAAQ;iBACjB;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACnD,MAAM,OAAO,GAAG;;oBAEA,CAAA;QAChB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,gEAAgE;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,OAAO;aACjB;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC/D,MAAM,OAAO,GAAG,mDAAmD,CAAA;QACnE,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,EAAE,EAAE,6BAA6B;aAC1C;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0CAA0C,EAAE,GAAG,EAAE;QACpD,MAAM,OAAO,GAAG;;;;;sBAKE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,0BAA0B;iBACnC;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACnE,MAAM,OAAO,GAAG;;;sBAGE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,kCAAkC;oBAC1C,MAAM,EAAE,iCAAiC;iBAC1C;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,yEAAyE,EAAE,GAAG,EAAE;QACnF,MAAM,OAAO,GAAG;;;sBAGE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,0BAA0B;oBAClC,MAAM,EAAE,iCAAiC;iBAC1C;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;QACpE,MAAM,OAAO,GAAG;;sBAEE,CAAA;QAClB,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;QAEpE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB;gBACE,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE;oBACN,MAAM,EAAE,8DAA8D;iBACvE;aACF;SACF,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolInfo } from '../tools';
|
|
2
|
+
export declare const toolUsePrompt: (tools: ToolInfo[], toolNamePrefix: string) => string;
|
|
3
|
+
export declare const responsePrompts: {
|
|
4
|
+
readonly errorInvokeTool: (tool: string, error: unknown) => string;
|
|
5
|
+
readonly requireUseTool: "Error: You must use a tool before proceeding";
|
|
6
|
+
readonly toolResults: (tool: string, result: string) => string;
|
|
7
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const toolInfoPrompt = (tool, toolNamePrefix, parameterPrefix) => `
|
|
2
|
+
## ${toolNamePrefix}${tool.name}
|
|
3
|
+
|
|
4
|
+
Description: ${tool.description}
|
|
5
|
+
|
|
6
|
+
Parameters:
|
|
7
|
+
${tool.parameters.map((param) => `- ${parameterPrefix}${param.name}: (${param.required ? 'required' : 'optional'}) ${param.description}`).join('\n')}
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
<${toolNamePrefix}${tool.name}>
|
|
11
|
+
${tool.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.usageValue}</${parameterPrefix}${param.name}>`).join('\n')}
|
|
12
|
+
</${toolNamePrefix}${tool.name}>`;
|
|
13
|
+
const toolInfoExamplesPrompt = (idx, tool, example, toolNamePrefix, parameterPrefix) => `
|
|
14
|
+
## Example ${idx + 1}: ${example.description}
|
|
15
|
+
|
|
16
|
+
<${toolNamePrefix}${tool.name}>
|
|
17
|
+
${example.parameters.map((param) => `<${parameterPrefix}${param.name}>${param.value}</${parameterPrefix}${param.name}>`).join('\n')}
|
|
18
|
+
</${toolNamePrefix}${tool.name}>
|
|
19
|
+
`;
|
|
20
|
+
export const toolUsePrompt = (tools, toolNamePrefix) => {
|
|
21
|
+
if (tools.length === 0) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
const parameterPrefix = `${toolNamePrefix}parameter_`;
|
|
25
|
+
let exampleIndex = 0;
|
|
26
|
+
return `
|
|
27
|
+
====
|
|
28
|
+
|
|
29
|
+
TOOL USE
|
|
30
|
+
|
|
31
|
+
You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.
|
|
32
|
+
|
|
33
|
+
# Tool Use Formatting
|
|
34
|
+
|
|
35
|
+
Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:
|
|
36
|
+
|
|
37
|
+
<${toolNamePrefix}tool_name>
|
|
38
|
+
<${parameterPrefix}name1>value1</${parameterPrefix}name1>
|
|
39
|
+
<${parameterPrefix}name2>value2</${parameterPrefix}name2>
|
|
40
|
+
...
|
|
41
|
+
</${toolNamePrefix}tool_name>
|
|
42
|
+
|
|
43
|
+
For example:
|
|
44
|
+
|
|
45
|
+
<${toolNamePrefix}read_file>
|
|
46
|
+
<${parameterPrefix}path>src/main.js</${parameterPrefix}path>
|
|
47
|
+
</${toolNamePrefix}read_file>
|
|
48
|
+
|
|
49
|
+
Always adhere to this format for the tool use to ensure proper parsing and execution.
|
|
50
|
+
|
|
51
|
+
# Tools
|
|
52
|
+
${tools.map((tool) => toolInfoPrompt(tool, toolNamePrefix, parameterPrefix)).join('\n')}
|
|
53
|
+
|
|
54
|
+
# Tool Use Examples
|
|
55
|
+
${tools
|
|
56
|
+
.map((tool) => {
|
|
57
|
+
let promp = '';
|
|
58
|
+
for (const example of tool.examples ?? []) {
|
|
59
|
+
promp += toolInfoExamplesPrompt(exampleIndex++, tool, example, toolNamePrefix, parameterPrefix);
|
|
60
|
+
}
|
|
61
|
+
return promp;
|
|
62
|
+
})
|
|
63
|
+
.join('')}
|
|
64
|
+
# Tool Use Guidelines
|
|
65
|
+
|
|
66
|
+
1. **In \`<thinking>\` tags**, assess what information you have and what you need to proceed.
|
|
67
|
+
2. **Choose one tool at a time per message** based on the task and its description. Do not assume a tool’s outcome without explicit confirmation.
|
|
68
|
+
3. **Formulate tool use only in the specified XML format** for each tool.
|
|
69
|
+
4. **Wait for the user’s response** after each tool use. Do not proceed until you have their confirmation.
|
|
70
|
+
5. The user’s response may include:
|
|
71
|
+
- Tool success or failure details
|
|
72
|
+
- Linter errors
|
|
73
|
+
- Terminal output or other relevant feedback
|
|
74
|
+
6. **Never repeat or quote the entire tool command** in your final user-facing message. Summarize outcomes clearly and avoid echoing commands verbatim.
|
|
75
|
+
7. **Respond concisely** and move the conversation forward. Do not re-issue the same command or re-trigger tool use without necessity.
|
|
76
|
+
8. Follow these steps **iteratively**, confirming success and addressing issues as you go.
|
|
77
|
+
|
|
78
|
+
By adhering to these guidelines:
|
|
79
|
+
- You maintain clarity without accidentally re-invoking tools.
|
|
80
|
+
- You confirm each step’s results before proceeding.
|
|
81
|
+
- You provide only the necessary information in user-facing replies to prevent re-interpretation as new commands.`;
|
|
82
|
+
};
|
|
83
|
+
export const responsePrompts = {
|
|
84
|
+
errorInvokeTool: (tool, error) => `An error occurred while invoking the tool "${tool}": ${error}`,
|
|
85
|
+
requireUseTool: 'Error: You must use a tool before proceeding',
|
|
86
|
+
toolResults: (tool, result) => `<tool_response>
|
|
87
|
+
<tool_name>${tool}</tool_name>
|
|
88
|
+
<tool_result>
|
|
89
|
+
${result}
|
|
90
|
+
</tool_result>
|
|
91
|
+
</tool_response>`,
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/Agent/prompts.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAAG,CAAC,IAAc,EAAE,cAAsB,EAAE,eAAuB,EAAE,EAAE,CAAC;KACvF,cAAc,GAAG,IAAI,CAAC,IAAI;;eAEhB,IAAI,CAAC,WAAW;;;EAG7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,eAAe,GAAG,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;GAGjJ,cAAc,GAAG,IAAI,CAAC,IAAI;EAC3B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,eAAe,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,eAAe,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IACjI,cAAc,GAAG,IAAI,CAAC,IAAI,GAAG,CAAA;AAEjC,MAAM,sBAAsB,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,OAAoB,EAAE,cAAsB,EAAE,eAAuB,EAAE,EAAE,CAAC;aAC1H,GAAG,GAAG,CAAC,KAAK,OAAO,CAAC,WAAW;;GAEzC,cAAc,GAAG,IAAI,CAAC,IAAI;EAC3B,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,eAAe,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,KAAK,eAAe,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;IAC/H,cAAc,GAAG,IAAI,CAAC,IAAI;CAC7B,CAAA;AAED,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAiB,EAAE,cAAsB,EAAE,EAAE;IACzE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,eAAe,GAAG,GAAG,cAAc,YAAY,CAAA;IAErD,IAAI,YAAY,GAAG,CAAC,CAAA;IAEpB,OAAO;;;;;;;;;;;GAWN,cAAc;GACd,eAAe,iBAAiB,eAAe;GAC/C,eAAe,iBAAiB,eAAe;;IAE9C,cAAc;;;;GAIf,cAAc;GACd,eAAe,qBAAqB,eAAe;IAClD,cAAc;;;;;EAKhB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGrF,KAAK;SACJ,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,IAAI,KAAK,GAAG,EAAE,CAAA;QACd,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;YAC1C,KAAK,IAAI,sBAAsB,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,CAAC,CAAA;QACjG,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;kHAkBuG,CAAA;AAClH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,eAAe,EAAE,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE,CAAC,8CAA8C,IAAI,MAAM,KAAK,EAAE;IAClH,cAAc,EAAE,8CAA8C;IAC9D,WAAW,EAAE,CAAC,IAAY,EAAE,MAAc,EAAE,EAAE,CAAC;aACpC,IAAI;;EAEf,MAAM;;iBAES;CACP,CAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Anthropic } from '@anthropic-ai/sdk';
|
|
2
|
+
import type { ModelInfo } from './ModelInfo';
|
|
3
|
+
export type ApiStreamChunk = ApiStreamTextChunk | ApiStreamUsageChunk;
|
|
4
|
+
export interface ApiStreamTextChunk {
|
|
5
|
+
type: 'text';
|
|
6
|
+
text: string;
|
|
7
|
+
}
|
|
8
|
+
export interface ApiStreamUsageChunk {
|
|
9
|
+
type: 'usage';
|
|
10
|
+
inputTokens: number;
|
|
11
|
+
outputTokens: number;
|
|
12
|
+
cacheWriteTokens?: number;
|
|
13
|
+
cacheReadTokens?: number;
|
|
14
|
+
totalCost?: number;
|
|
15
|
+
}
|
|
16
|
+
export type ApiStream = AsyncGenerator<ApiStreamChunk>;
|
|
17
|
+
export interface AiServiceOptions {
|
|
18
|
+
modelId?: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
baseUrl?: string;
|
|
21
|
+
}
|
|
22
|
+
export type MessageParam = Anthropic.Messages.MessageParam;
|
|
23
|
+
export declare abstract class AiServiceBase {
|
|
24
|
+
abstract get model(): {
|
|
25
|
+
id: string;
|
|
26
|
+
info: ModelInfo;
|
|
27
|
+
};
|
|
28
|
+
abstract send(systemPrompt: string, messages: MessageParam[]): ApiStream;
|
|
29
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AiServiceBase.js","sourceRoot":"","sources":["../../src/AiService/AiServiceBase.ts"],"names":[],"mappings":"AA8BA,MAAM,OAAgB,aAAa;CAIlC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AiServiceBase, type AiServiceOptions, type ApiStream, type MessageParam } from './AiServiceBase';
|
|
2
|
+
import { type AnthropicModelId, type ModelInfo } from './ModelInfo';
|
|
3
|
+
export declare class AnthropicService extends AiServiceBase {
|
|
4
|
+
#private;
|
|
5
|
+
readonly model: {
|
|
6
|
+
id: AnthropicModelId;
|
|
7
|
+
info: ModelInfo;
|
|
8
|
+
};
|
|
9
|
+
constructor(options: AiServiceOptions);
|
|
10
|
+
send(systemPrompt: string, messages: MessageParam[]): ApiStream;
|
|
11
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// source: https://github.com/cline/cline/blob/f6c19c29a64ca84e9360df7ab2c07d128dcebe64/src/api/providers/anthropic.ts
|
|
2
|
+
import { Anthropic } from '@anthropic-ai/sdk';
|
|
3
|
+
import { createServiceLogger } from '../logger';
|
|
4
|
+
import { AiServiceBase } from './AiServiceBase';
|
|
5
|
+
import { anthropicDefaultModelId, anthropicModels } from './ModelInfo';
|
|
6
|
+
const logger = createServiceLogger('AnthropicService');
|
|
7
|
+
export class AnthropicService extends AiServiceBase {
|
|
8
|
+
#options;
|
|
9
|
+
#client;
|
|
10
|
+
model;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super();
|
|
13
|
+
this.#options = options;
|
|
14
|
+
this.#client = new Anthropic({
|
|
15
|
+
apiKey: options.apiKey,
|
|
16
|
+
baseURL: options.baseUrl || undefined,
|
|
17
|
+
});
|
|
18
|
+
const id = (this.#options.modelId ?? anthropicDefaultModelId);
|
|
19
|
+
this.model = {
|
|
20
|
+
id,
|
|
21
|
+
info: anthropicModels[id] ?? anthropicModels[anthropicDefaultModelId],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async *send(systemPrompt, messages) {
|
|
25
|
+
logger.debug({ modelId: this.model.id, messagesCount: messages.length }, 'Starting message stream');
|
|
26
|
+
let stream;
|
|
27
|
+
const modelId = this.model.id;
|
|
28
|
+
switch (modelId) {
|
|
29
|
+
// 'latest' alias does not support cache_control
|
|
30
|
+
case 'claude-3-5-sonnet-20241022':
|
|
31
|
+
case 'claude-3-5-haiku-20241022':
|
|
32
|
+
case 'claude-3-opus-20240229':
|
|
33
|
+
case 'claude-3-haiku-20240307': {
|
|
34
|
+
/*
|
|
35
|
+
The latest message will be the new user message, one before will be the assistant message from a previous request, and the user message before that will be a previously cached user message. So we need to mark the latest user message as ephemeral to cache it for the next request, and mark the second to last user message as ephemeral to let the server know the last message to retrieve from the cache for the current request..
|
|
36
|
+
*/
|
|
37
|
+
const userMsgIndices = messages.reduce((acc, msg, index) => {
|
|
38
|
+
if (msg.role === 'user') {
|
|
39
|
+
acc.push(index);
|
|
40
|
+
}
|
|
41
|
+
return acc;
|
|
42
|
+
}, []);
|
|
43
|
+
const lastUserMsgIndex = userMsgIndices[userMsgIndices.length - 1] ?? -1;
|
|
44
|
+
const secondLastMsgUserIndex = userMsgIndices[userMsgIndices.length - 2] ?? -1;
|
|
45
|
+
stream = await this.#client.messages.create({
|
|
46
|
+
model: modelId,
|
|
47
|
+
max_tokens: this.model.info.maxTokens || 8192,
|
|
48
|
+
temperature: 0,
|
|
49
|
+
system: [
|
|
50
|
+
{
|
|
51
|
+
text: systemPrompt,
|
|
52
|
+
type: 'text',
|
|
53
|
+
cache_control: { type: 'ephemeral' },
|
|
54
|
+
},
|
|
55
|
+
], // setting cache breakpoint for system prompt so new tasks can reuse it
|
|
56
|
+
messages: messages.map((message, index) => {
|
|
57
|
+
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
|
|
58
|
+
return {
|
|
59
|
+
...message,
|
|
60
|
+
content: typeof message.content === 'string'
|
|
61
|
+
? [
|
|
62
|
+
{
|
|
63
|
+
type: 'text',
|
|
64
|
+
text: message.content,
|
|
65
|
+
cache_control: {
|
|
66
|
+
type: 'ephemeral',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
]
|
|
70
|
+
: message.content.map((content, contentIndex) => contentIndex === message.content.length - 1
|
|
71
|
+
? {
|
|
72
|
+
...content,
|
|
73
|
+
cache_control: {
|
|
74
|
+
type: 'ephemeral',
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
: content),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return message;
|
|
81
|
+
}),
|
|
82
|
+
// tools, // cache breakpoints go from tools > system > messages, and since tools dont change, we can just set the breakpoint at the end of system (this avoids having to set a breakpoint at the end of tools which by itself does not meet min requirements for haiku caching)
|
|
83
|
+
// tool_choice: { type: "auto" },
|
|
84
|
+
// tools: tools,
|
|
85
|
+
stream: true,
|
|
86
|
+
}, (() => {
|
|
87
|
+
// prompt caching: https://x.com/alexalbert__/status/1823751995901272068
|
|
88
|
+
// https://github.com/anthropics/anthropic-sdk-typescript?tab=readme-ov-file#default-headers
|
|
89
|
+
// https://github.com/anthropics/anthropic-sdk-typescript/commit/c920b77fc67bd839bfeb6716ceab9d7c9bbe7393
|
|
90
|
+
switch (modelId) {
|
|
91
|
+
case 'claude-3-5-sonnet-20241022':
|
|
92
|
+
case 'claude-3-5-haiku-20241022':
|
|
93
|
+
case 'claude-3-opus-20240229':
|
|
94
|
+
case 'claude-3-haiku-20240307':
|
|
95
|
+
return {
|
|
96
|
+
headers: {
|
|
97
|
+
'anthropic-beta': 'prompt-caching-2024-07-31',
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
default:
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
})());
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
default: {
|
|
107
|
+
stream = await this.#client.messages.create({
|
|
108
|
+
model: modelId,
|
|
109
|
+
max_tokens: this.model.info.maxTokens || 8192,
|
|
110
|
+
temperature: 0,
|
|
111
|
+
system: [{ text: systemPrompt, type: 'text' }],
|
|
112
|
+
messages,
|
|
113
|
+
// tools,
|
|
114
|
+
// tool_choice: { type: "auto" },
|
|
115
|
+
stream: true,
|
|
116
|
+
});
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
logger.debug('Stream created, processing chunks');
|
|
121
|
+
for await (const chunk of stream) {
|
|
122
|
+
switch (chunk.type) {
|
|
123
|
+
case 'message_start': {
|
|
124
|
+
// tells us cache reads/writes/input/output
|
|
125
|
+
const usage = chunk.message.usage;
|
|
126
|
+
const usageInfo = {
|
|
127
|
+
type: 'usage',
|
|
128
|
+
inputTokens: usage.input_tokens || 0,
|
|
129
|
+
outputTokens: usage.output_tokens || 0,
|
|
130
|
+
cacheWriteTokens: usage.cache_creation_input_tokens || undefined,
|
|
131
|
+
cacheReadTokens: usage.cache_read_input_tokens || undefined,
|
|
132
|
+
};
|
|
133
|
+
logger.trace({ usage: usageInfo }, 'Message start usage');
|
|
134
|
+
yield usageInfo;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
case 'message_delta': {
|
|
138
|
+
// tells us stop_reason, stop_sequence, and output tokens along the way and at the end of the message
|
|
139
|
+
const deltaUsage = {
|
|
140
|
+
type: 'usage',
|
|
141
|
+
inputTokens: 0,
|
|
142
|
+
outputTokens: chunk.usage.output_tokens || 0,
|
|
143
|
+
};
|
|
144
|
+
logger.trace({ usage: deltaUsage }, 'Message delta usage');
|
|
145
|
+
yield deltaUsage;
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
case 'message_stop':
|
|
149
|
+
logger.debug('Message stream completed');
|
|
150
|
+
break;
|
|
151
|
+
case 'content_block_start':
|
|
152
|
+
switch (chunk.content_block.type) {
|
|
153
|
+
case 'text':
|
|
154
|
+
// we may receive multiple text blocks, in which case just insert a line break between them
|
|
155
|
+
if (chunk.index > 0) {
|
|
156
|
+
yield {
|
|
157
|
+
type: 'text',
|
|
158
|
+
text: '\n',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
yield {
|
|
162
|
+
type: 'text',
|
|
163
|
+
text: chunk.content_block.text,
|
|
164
|
+
};
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case 'content_block_delta':
|
|
169
|
+
switch (chunk.delta.type) {
|
|
170
|
+
case 'text_delta':
|
|
171
|
+
yield {
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: chunk.delta.text,
|
|
174
|
+
};
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
case 'content_block_stop':
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
logger.debug('Stream ended');
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=AnthropicService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AnthropicService.js","sourceRoot":"","sources":["../../src/AiService/AnthropicService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AiServiceBase, type AiServiceOptions, type ApiStream, type MessageParam } from './AiServiceBase';
|
|
2
|
+
import { type ModelInfo } from './ModelInfo';
|
|
3
|
+
export declare class DeepSeekService extends AiServiceBase {
|
|
4
|
+
#private;
|
|
5
|
+
readonly model: {
|
|
6
|
+
id: string;
|
|
7
|
+
info: ModelInfo;
|
|
8
|
+
};
|
|
9
|
+
constructor(options: AiServiceOptions);
|
|
10
|
+
send(systemPrompt: string, messages: MessageParam[]): ApiStream;
|
|
11
|
+
}
|