agentic-kit 0.3.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -32
- package/esm/event-stream.js +77 -0
- package/esm/index.js +151 -41
- package/esm/messages.js +130 -0
- package/esm/model-registry.js +26 -0
- package/esm/package.json +1 -0
- package/esm/provider-registry.js +20 -0
- package/esm/transform-messages.js +139 -0
- package/esm/types.js +1 -0
- package/event-stream.d.ts +19 -0
- package/event-stream.js +83 -0
- package/index.d.ts +26 -30
- package/index.js +179 -42
- package/messages.d.ts +31 -0
- package/messages.js +144 -0
- package/model-registry.d.ts +7 -0
- package/model-registry.js +34 -0
- package/package.json +15 -8
- package/provider-registry.d.ts +6 -0
- package/provider-registry.js +27 -0
- package/transform-messages.d.ts +2 -0
- package/transform-messages.js +142 -0
- package/types.d.ts +231 -0
- package/types.js +2 -0
package/messages.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEmptyUsage = createEmptyUsage;
|
|
4
|
+
exports.calculateUsageCost = calculateUsageCost;
|
|
5
|
+
exports.createAssistantMessage = createAssistantMessage;
|
|
6
|
+
exports.createTextContent = createTextContent;
|
|
7
|
+
exports.createImageContent = createImageContent;
|
|
8
|
+
exports.createToolCall = createToolCall;
|
|
9
|
+
exports.createUserMessage = createUserMessage;
|
|
10
|
+
exports.createToolResultMessage = createToolResultMessage;
|
|
11
|
+
exports.getMessageText = getMessageText;
|
|
12
|
+
exports.injectDeferralResults = injectDeferralResults;
|
|
13
|
+
exports.cloneMessage = cloneMessage;
|
|
14
|
+
exports.normalizeContext = normalizeContext;
|
|
15
|
+
function createEmptyUsage() {
|
|
16
|
+
return {
|
|
17
|
+
input: 0,
|
|
18
|
+
output: 0,
|
|
19
|
+
cacheRead: 0,
|
|
20
|
+
cacheWrite: 0,
|
|
21
|
+
totalTokens: 0,
|
|
22
|
+
cost: {
|
|
23
|
+
input: 0,
|
|
24
|
+
output: 0,
|
|
25
|
+
cacheRead: 0,
|
|
26
|
+
cacheWrite: 0,
|
|
27
|
+
total: 0,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function calculateUsageCost(model, usage) {
|
|
32
|
+
const schedule = model.cost;
|
|
33
|
+
usage.cost.input = ((schedule?.input ?? 0) / 1_000_000) * usage.input;
|
|
34
|
+
usage.cost.output = ((schedule?.output ?? 0) / 1_000_000) * usage.output;
|
|
35
|
+
usage.cost.cacheRead = ((schedule?.cacheRead ?? 0) / 1_000_000) * usage.cacheRead;
|
|
36
|
+
usage.cost.cacheWrite = ((schedule?.cacheWrite ?? 0) / 1_000_000) * usage.cacheWrite;
|
|
37
|
+
usage.cost.total =
|
|
38
|
+
usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
|
|
39
|
+
return usage.cost;
|
|
40
|
+
}
|
|
41
|
+
function createAssistantMessage(model) {
|
|
42
|
+
return {
|
|
43
|
+
role: 'assistant',
|
|
44
|
+
api: model.api,
|
|
45
|
+
provider: model.provider,
|
|
46
|
+
model: model.id,
|
|
47
|
+
content: [],
|
|
48
|
+
usage: createEmptyUsage(),
|
|
49
|
+
stopReason: 'stop',
|
|
50
|
+
timestamp: Date.now(),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function createTextContent(text = '') {
|
|
54
|
+
return { type: 'text', text };
|
|
55
|
+
}
|
|
56
|
+
function createImageContent(data, mimeType) {
|
|
57
|
+
return { type: 'image', data, mimeType };
|
|
58
|
+
}
|
|
59
|
+
function createToolCall(id, name) {
|
|
60
|
+
return { type: 'toolCall', id, name, arguments: {}, rawArguments: '' };
|
|
61
|
+
}
|
|
62
|
+
function createUserMessage(content) {
|
|
63
|
+
return {
|
|
64
|
+
role: 'user',
|
|
65
|
+
content,
|
|
66
|
+
timestamp: Date.now(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function createToolResultMessage(toolCallId, toolName, content, isError = false) {
|
|
70
|
+
return {
|
|
71
|
+
role: 'toolResult',
|
|
72
|
+
toolCallId,
|
|
73
|
+
toolName,
|
|
74
|
+
content,
|
|
75
|
+
isError,
|
|
76
|
+
timestamp: Date.now(),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function getMessageText(message) {
|
|
80
|
+
return message.content
|
|
81
|
+
.filter((block) => block.type === 'text')
|
|
82
|
+
.map((block) => block.text)
|
|
83
|
+
.join('');
|
|
84
|
+
}
|
|
85
|
+
const DEFAULT_DEFERRAL_TEXT = 'User did not respond. Continue.';
|
|
86
|
+
/**
|
|
87
|
+
* Synthesize toolResult messages for every toolCall that lacks both a decision
|
|
88
|
+
* and a paired toolResult. Returns input unchanged (referentially equal) when
|
|
89
|
+
* nothing needs synthesizing.
|
|
90
|
+
*
|
|
91
|
+
* Use case: user types a message instead of clicking approve/deny on a paused
|
|
92
|
+
* tool. The agent can't resume on text alone — every dangling toolCall needs
|
|
93
|
+
* a result before the next request. Compose with sendMessages to forward the
|
|
94
|
+
* conversation cleanly:
|
|
95
|
+
*
|
|
96
|
+
* await sendMessages([...injectDeferralResults(messages), createUserMessage(text)]);
|
|
97
|
+
*/
|
|
98
|
+
function injectDeferralResults(messages, optionsOrText = {}) {
|
|
99
|
+
const opts = typeof optionsOrText === 'string' ? { deferralText: optionsOrText } : optionsOrText;
|
|
100
|
+
const deferralText = opts.deferralText ?? DEFAULT_DEFERRAL_TEXT;
|
|
101
|
+
const completed = new Set();
|
|
102
|
+
for (const m of messages) {
|
|
103
|
+
if (m.role === 'toolResult')
|
|
104
|
+
completed.add(m.toolCallId);
|
|
105
|
+
}
|
|
106
|
+
const synthetic = [];
|
|
107
|
+
for (const m of messages) {
|
|
108
|
+
if (m.role !== 'assistant')
|
|
109
|
+
continue;
|
|
110
|
+
for (const block of m.content) {
|
|
111
|
+
if (block.type !== 'toolCall')
|
|
112
|
+
continue;
|
|
113
|
+
if (completed.has(block.id))
|
|
114
|
+
continue;
|
|
115
|
+
if ('decision' in block && block.decision !== undefined)
|
|
116
|
+
continue;
|
|
117
|
+
const result = createToolResultMessage(block.id, block.name, [
|
|
118
|
+
{ type: 'text', text: deferralText },
|
|
119
|
+
]);
|
|
120
|
+
if (opts.details !== undefined)
|
|
121
|
+
result.details = opts.details;
|
|
122
|
+
synthetic.push(result);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (synthetic.length === 0)
|
|
126
|
+
return messages;
|
|
127
|
+
return [...messages, ...synthetic];
|
|
128
|
+
}
|
|
129
|
+
function cloneMessage(message) {
|
|
130
|
+
return JSON.parse(JSON.stringify(message));
|
|
131
|
+
}
|
|
132
|
+
function normalizeContext(context) {
|
|
133
|
+
return {
|
|
134
|
+
systemPrompt: context.systemPrompt,
|
|
135
|
+
tools: context.tools ?? [],
|
|
136
|
+
messages: context.messages.map((message) => ensureTimestamp(cloneMessage(message))),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function ensureTimestamp(message) {
|
|
140
|
+
if (typeof message.timestamp !== 'number') {
|
|
141
|
+
message.timestamp = Date.now();
|
|
142
|
+
}
|
|
143
|
+
return message;
|
|
144
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ModelDescriptor } from './types.js';
|
|
2
|
+
export declare function registerModel(model: ModelDescriptor): void;
|
|
3
|
+
export declare function registerModels(models: ModelDescriptor[]): void;
|
|
4
|
+
export declare function getModel(provider: string, modelId: string): ModelDescriptor | undefined;
|
|
5
|
+
export declare function getModels(provider?: string): ModelDescriptor[];
|
|
6
|
+
export declare function getProviders(): string[];
|
|
7
|
+
export declare function clearModels(): void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerModel = registerModel;
|
|
4
|
+
exports.registerModels = registerModels;
|
|
5
|
+
exports.getModel = getModel;
|
|
6
|
+
exports.getModels = getModels;
|
|
7
|
+
exports.getProviders = getProviders;
|
|
8
|
+
exports.clearModels = clearModels;
|
|
9
|
+
const modelsByProvider = new Map();
|
|
10
|
+
function registerModel(model) {
|
|
11
|
+
const providerModels = modelsByProvider.get(model.provider) ?? new Map();
|
|
12
|
+
providerModels.set(model.id, model);
|
|
13
|
+
modelsByProvider.set(model.provider, providerModels);
|
|
14
|
+
}
|
|
15
|
+
function registerModels(models) {
|
|
16
|
+
for (const model of models) {
|
|
17
|
+
registerModel(model);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function getModel(provider, modelId) {
|
|
21
|
+
return modelsByProvider.get(provider)?.get(modelId);
|
|
22
|
+
}
|
|
23
|
+
function getModels(provider) {
|
|
24
|
+
if (provider) {
|
|
25
|
+
return Array.from(modelsByProvider.get(provider)?.values() ?? []);
|
|
26
|
+
}
|
|
27
|
+
return Array.from(modelsByProvider.values()).flatMap((entries) => Array.from(entries.values()));
|
|
28
|
+
}
|
|
29
|
+
function getProviders() {
|
|
30
|
+
return Array.from(modelsByProvider.keys());
|
|
31
|
+
}
|
|
32
|
+
function clearModels() {
|
|
33
|
+
modelsByProvider.clear();
|
|
34
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentic-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"author": "Dan Lynch <pyramation@gmail.com>",
|
|
5
5
|
"description": "Provider-agnostic LLM adapter with streaming and multi-turn support",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "esm/index.js",
|
|
8
8
|
"types": "index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./index.d.ts",
|
|
12
|
+
"import": "./esm/index.js",
|
|
13
|
+
"require": "./index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
9
16
|
"homepage": "https://github.com/constructive-io/agentic-kit",
|
|
10
17
|
"license": "SEE LICENSE IN LICENSE",
|
|
11
18
|
"publishConfig": {
|
|
@@ -21,19 +28,19 @@
|
|
|
21
28
|
},
|
|
22
29
|
"scripts": {
|
|
23
30
|
"clean": "makage clean",
|
|
31
|
+
"prepack": "npm run build",
|
|
24
32
|
"build": "makage build",
|
|
33
|
+
"postbuild": "node ../../scripts/write-esm-package-json.js",
|
|
25
34
|
"build:dev": "makage build --dev",
|
|
26
35
|
"lint": "eslint . --fix",
|
|
27
36
|
"test": "jest",
|
|
28
37
|
"test:watch": "jest --watch"
|
|
29
38
|
},
|
|
30
39
|
"dependencies": {
|
|
31
|
-
"@agentic-kit/anthropic": "
|
|
32
|
-
"@agentic-kit/ollama": "
|
|
33
|
-
"@agentic-kit/openai": "
|
|
34
|
-
},
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"cross-fetch": "^4.1.0"
|
|
40
|
+
"@agentic-kit/anthropic": "1.2.0",
|
|
41
|
+
"@agentic-kit/ollama": "1.2.0",
|
|
42
|
+
"@agentic-kit/openai": "1.2.0"
|
|
37
43
|
},
|
|
38
|
-
"keywords": []
|
|
44
|
+
"keywords": [],
|
|
45
|
+
"gitHead": "d4f3f660be621267efe12671c22db202ccdb3f0b"
|
|
39
46
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ProviderAdapter } from './types.js';
|
|
2
|
+
export declare function registerProvider(adapter: ProviderAdapter, sourceId?: string): void;
|
|
3
|
+
export declare function getProvider(api: string): ProviderAdapter | undefined;
|
|
4
|
+
export declare function getProviders(): ProviderAdapter[];
|
|
5
|
+
export declare function unregisterProviders(sourceId: string): void;
|
|
6
|
+
export declare function clearProviders(): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerProvider = registerProvider;
|
|
4
|
+
exports.getProvider = getProvider;
|
|
5
|
+
exports.getProviders = getProviders;
|
|
6
|
+
exports.unregisterProviders = unregisterProviders;
|
|
7
|
+
exports.clearProviders = clearProviders;
|
|
8
|
+
const providersByApi = new Map();
|
|
9
|
+
function registerProvider(adapter, sourceId) {
|
|
10
|
+
providersByApi.set(adapter.api, { adapter, sourceId });
|
|
11
|
+
}
|
|
12
|
+
function getProvider(api) {
|
|
13
|
+
return providersByApi.get(api)?.adapter;
|
|
14
|
+
}
|
|
15
|
+
function getProviders() {
|
|
16
|
+
return Array.from(providersByApi.values(), (entry) => entry.adapter);
|
|
17
|
+
}
|
|
18
|
+
function unregisterProviders(sourceId) {
|
|
19
|
+
for (const [api, entry] of providersByApi.entries()) {
|
|
20
|
+
if (entry.sourceId === sourceId) {
|
|
21
|
+
providersByApi.delete(api);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function clearProviders() {
|
|
26
|
+
providersByApi.clear();
|
|
27
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.transformMessages = transformMessages;
|
|
4
|
+
function transformMessages(messages, model) {
|
|
5
|
+
const toolCallIdMap = new Map();
|
|
6
|
+
const transformed = messages.flatMap((message) => {
|
|
7
|
+
if (message.role !== 'assistant') {
|
|
8
|
+
if (message.role === 'toolResult') {
|
|
9
|
+
const normalizedId = toolCallIdMap.get(message.toolCallId);
|
|
10
|
+
if (normalizedId && normalizedId !== message.toolCallId) {
|
|
11
|
+
return [{ ...message, toolCallId: normalizedId }];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return [message];
|
|
15
|
+
}
|
|
16
|
+
if (message.stopReason === 'error' || message.stopReason === 'aborted') {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const sameModel = message.provider === model.provider &&
|
|
20
|
+
message.api === model.api &&
|
|
21
|
+
message.model === model.id;
|
|
22
|
+
const content = message.content.flatMap((block) => {
|
|
23
|
+
if (block.type === 'thinking') {
|
|
24
|
+
if (sameModel) {
|
|
25
|
+
return [block];
|
|
26
|
+
}
|
|
27
|
+
if (!block.thinking.trim()) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
const thinkingAsText = {
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: `<thinking>${block.thinking}</thinking>`,
|
|
33
|
+
};
|
|
34
|
+
return [thinkingAsText];
|
|
35
|
+
}
|
|
36
|
+
if (block.type === 'toolCall') {
|
|
37
|
+
const normalizedId = normalizeToolCallId(block.id, model);
|
|
38
|
+
if (normalizedId !== block.id) {
|
|
39
|
+
toolCallIdMap.set(block.id, normalizedId);
|
|
40
|
+
}
|
|
41
|
+
const toolCall = normalizedId === block.id ? block : { ...block, id: normalizedId };
|
|
42
|
+
return [toolCall];
|
|
43
|
+
}
|
|
44
|
+
return [block];
|
|
45
|
+
});
|
|
46
|
+
return [{ ...message, content }];
|
|
47
|
+
});
|
|
48
|
+
return insertSyntheticToolResults(transformed);
|
|
49
|
+
}
|
|
50
|
+
function insertSyntheticToolResults(messages) {
|
|
51
|
+
const result = [];
|
|
52
|
+
let pendingToolCalls = [];
|
|
53
|
+
let seenToolResults = new Set();
|
|
54
|
+
for (const message of messages) {
|
|
55
|
+
if (message.role === 'assistant') {
|
|
56
|
+
flushPendingToolCalls(result, pendingToolCalls, seenToolResults);
|
|
57
|
+
pendingToolCalls = message.content.filter((block) => block.type === 'toolCall');
|
|
58
|
+
seenToolResults = new Set();
|
|
59
|
+
result.push(message);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (message.role === 'toolResult') {
|
|
63
|
+
seenToolResults.add(message.toolCallId);
|
|
64
|
+
result.push(message);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
flushPendingToolCalls(result, pendingToolCalls, seenToolResults);
|
|
68
|
+
pendingToolCalls = [];
|
|
69
|
+
seenToolResults = new Set();
|
|
70
|
+
result.push(message);
|
|
71
|
+
}
|
|
72
|
+
flushPendingToolCalls(result, pendingToolCalls, seenToolResults);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
function flushPendingToolCalls(result, pendingToolCalls, seenToolResults) {
|
|
76
|
+
if (pendingToolCalls.length === 0) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
for (const toolCall of pendingToolCalls) {
|
|
80
|
+
if (seenToolResults.has(toolCall.id)) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const synthetic = {
|
|
84
|
+
role: 'toolResult',
|
|
85
|
+
toolCallId: toolCall.id,
|
|
86
|
+
toolName: toolCall.name,
|
|
87
|
+
content: [{ type: 'text', text: 'No result provided.' }],
|
|
88
|
+
isError: true,
|
|
89
|
+
timestamp: Date.now(),
|
|
90
|
+
};
|
|
91
|
+
result.push(synthetic);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function normalizeToolCallId(id, model) {
|
|
95
|
+
const format = model.compat?.toolCallIdFormat ?? defaultToolCallIdFormat(model);
|
|
96
|
+
if (format === 'passthrough') {
|
|
97
|
+
return id;
|
|
98
|
+
}
|
|
99
|
+
if (format === 'mistral9') {
|
|
100
|
+
const alphanumeric = id.replace(/[^a-zA-Z0-9]/g, '');
|
|
101
|
+
if (alphanumeric.length >= 9) {
|
|
102
|
+
return alphanumeric.slice(0, 9);
|
|
103
|
+
}
|
|
104
|
+
return stableAlphanumericId(id, 9);
|
|
105
|
+
}
|
|
106
|
+
const safe = id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
|
|
107
|
+
if (safe.length > 0) {
|
|
108
|
+
return safe;
|
|
109
|
+
}
|
|
110
|
+
return stableId(id, 24, /^[a-zA-Z0-9_-]+$/);
|
|
111
|
+
}
|
|
112
|
+
function defaultToolCallIdFormat(model) {
|
|
113
|
+
if (model.provider === 'anthropic' || model.api === 'anthropic-messages') {
|
|
114
|
+
return 'safe64';
|
|
115
|
+
}
|
|
116
|
+
return 'passthrough';
|
|
117
|
+
}
|
|
118
|
+
function stableId(input, length, pattern) {
|
|
119
|
+
let hash = 0;
|
|
120
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
121
|
+
hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
|
|
122
|
+
}
|
|
123
|
+
let value = `tc_${hash.toString(36)}`;
|
|
124
|
+
while (!pattern.test(value)) {
|
|
125
|
+
value = value.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
126
|
+
}
|
|
127
|
+
if (value.length >= length) {
|
|
128
|
+
return value.slice(0, length);
|
|
129
|
+
}
|
|
130
|
+
return value.padEnd(length, '0');
|
|
131
|
+
}
|
|
132
|
+
function stableAlphanumericId(input, length) {
|
|
133
|
+
let hash = 0;
|
|
134
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
135
|
+
hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
|
|
136
|
+
}
|
|
137
|
+
const value = `tc${hash.toString(36)}`.replace(/[^a-zA-Z0-9]/g, '');
|
|
138
|
+
if (value.length >= length) {
|
|
139
|
+
return value.slice(0, length);
|
|
140
|
+
}
|
|
141
|
+
return value.padEnd(length, '0');
|
|
142
|
+
}
|
package/types.d.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
3
|
+
export interface JsonObject {
|
|
4
|
+
[key: string]: JsonValue | undefined;
|
|
5
|
+
}
|
|
6
|
+
export interface JsonSchema {
|
|
7
|
+
$id?: string;
|
|
8
|
+
$ref?: string;
|
|
9
|
+
additionalProperties?: boolean | JsonSchema;
|
|
10
|
+
allOf?: JsonSchema[];
|
|
11
|
+
anyOf?: JsonSchema[];
|
|
12
|
+
const?: JsonValue;
|
|
13
|
+
default?: JsonValue;
|
|
14
|
+
description?: string;
|
|
15
|
+
enum?: JsonValue[];
|
|
16
|
+
format?: string;
|
|
17
|
+
items?: JsonSchema | JsonSchema[];
|
|
18
|
+
maxItems?: number;
|
|
19
|
+
maxLength?: number;
|
|
20
|
+
maximum?: number;
|
|
21
|
+
minItems?: number;
|
|
22
|
+
minLength?: number;
|
|
23
|
+
minimum?: number;
|
|
24
|
+
oneOf?: JsonSchema[];
|
|
25
|
+
pattern?: string;
|
|
26
|
+
properties?: Record<string, JsonSchema>;
|
|
27
|
+
required?: string[];
|
|
28
|
+
title?: string;
|
|
29
|
+
type?: string | string[];
|
|
30
|
+
}
|
|
31
|
+
export type InputCapability = 'text' | 'image';
|
|
32
|
+
export interface CostSchedule {
|
|
33
|
+
input?: number;
|
|
34
|
+
output?: number;
|
|
35
|
+
cacheRead?: number;
|
|
36
|
+
cacheWrite?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface OpenAICompatibleCompat {
|
|
39
|
+
maxTokensField?: 'max_completion_tokens' | 'max_tokens';
|
|
40
|
+
reasoningFormat?: 'none' | 'openai';
|
|
41
|
+
supportsReasoningEffort?: boolean;
|
|
42
|
+
supportsStrictToolSchema?: boolean;
|
|
43
|
+
supportsUsageInStreaming?: boolean;
|
|
44
|
+
toolCallIdFormat?: 'passthrough' | 'safe64' | 'mistral9';
|
|
45
|
+
requiresToolResultName?: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface ModelDescriptor {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
api: string;
|
|
51
|
+
provider: string;
|
|
52
|
+
baseUrl: string;
|
|
53
|
+
input: InputCapability[];
|
|
54
|
+
reasoning: boolean;
|
|
55
|
+
tools?: boolean;
|
|
56
|
+
contextWindow?: number;
|
|
57
|
+
maxOutputTokens?: number;
|
|
58
|
+
cost?: CostSchedule;
|
|
59
|
+
headers?: Record<string, string>;
|
|
60
|
+
compat?: OpenAICompatibleCompat;
|
|
61
|
+
}
|
|
62
|
+
export interface TextContent {
|
|
63
|
+
type: 'text';
|
|
64
|
+
text: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ImageContent {
|
|
67
|
+
type: 'image';
|
|
68
|
+
data: string;
|
|
69
|
+
mimeType: string;
|
|
70
|
+
}
|
|
71
|
+
export interface ThinkingContent {
|
|
72
|
+
type: 'thinking';
|
|
73
|
+
thinking: string;
|
|
74
|
+
signature?: string;
|
|
75
|
+
}
|
|
76
|
+
export interface ToolCallContent {
|
|
77
|
+
type: 'toolCall';
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
arguments: Record<string, JsonValue | undefined>;
|
|
81
|
+
rawArguments?: string;
|
|
82
|
+
decision?: unknown;
|
|
83
|
+
}
|
|
84
|
+
export interface Usage {
|
|
85
|
+
input: number;
|
|
86
|
+
output: number;
|
|
87
|
+
cacheRead: number;
|
|
88
|
+
cacheWrite: number;
|
|
89
|
+
totalTokens: number;
|
|
90
|
+
cost: {
|
|
91
|
+
input: number;
|
|
92
|
+
output: number;
|
|
93
|
+
cacheRead: number;
|
|
94
|
+
cacheWrite: number;
|
|
95
|
+
total: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export type StopReason = 'stop' | 'length' | 'toolUse' | 'error' | 'aborted';
|
|
99
|
+
export interface UserMessage {
|
|
100
|
+
role: 'user';
|
|
101
|
+
content: string | Array<TextContent | ImageContent>;
|
|
102
|
+
timestamp: number;
|
|
103
|
+
}
|
|
104
|
+
export interface AssistantMessage {
|
|
105
|
+
role: 'assistant';
|
|
106
|
+
content: Array<TextContent | ThinkingContent | ToolCallContent>;
|
|
107
|
+
api: string;
|
|
108
|
+
provider: string;
|
|
109
|
+
model: string;
|
|
110
|
+
usage: Usage;
|
|
111
|
+
stopReason: StopReason;
|
|
112
|
+
errorMessage?: string;
|
|
113
|
+
timestamp: number;
|
|
114
|
+
}
|
|
115
|
+
export interface ToolResultMessage<TDetails = unknown> {
|
|
116
|
+
role: 'toolResult';
|
|
117
|
+
toolCallId: string;
|
|
118
|
+
toolName: string;
|
|
119
|
+
content: Array<TextContent | ImageContent>;
|
|
120
|
+
isError: boolean;
|
|
121
|
+
details?: TDetails;
|
|
122
|
+
timestamp: number;
|
|
123
|
+
}
|
|
124
|
+
export type Message = UserMessage | AssistantMessage | ToolResultMessage;
|
|
125
|
+
export interface ToolDefinition<TSchema extends JsonSchema = JsonSchema> {
|
|
126
|
+
name: string;
|
|
127
|
+
description: string;
|
|
128
|
+
parameters: TSchema;
|
|
129
|
+
}
|
|
130
|
+
export interface Context {
|
|
131
|
+
systemPrompt?: string;
|
|
132
|
+
messages: Message[];
|
|
133
|
+
tools?: ToolDefinition[];
|
|
134
|
+
}
|
|
135
|
+
export type CacheRetention = 'none' | 'short' | 'long';
|
|
136
|
+
export interface StreamOptions {
|
|
137
|
+
apiKey?: string;
|
|
138
|
+
cacheRetention?: CacheRetention;
|
|
139
|
+
headers?: Record<string, string>;
|
|
140
|
+
maxRetryDelayMs?: number;
|
|
141
|
+
maxTokens?: number;
|
|
142
|
+
metadata?: Record<string, JsonValue | undefined>;
|
|
143
|
+
onPayload?: (payload: unknown) => void;
|
|
144
|
+
reasoning?: 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
145
|
+
sessionId?: string;
|
|
146
|
+
signal?: AbortSignal;
|
|
147
|
+
temperature?: number;
|
|
148
|
+
}
|
|
149
|
+
export type AssistantMessageEvent = {
|
|
150
|
+
type: 'start';
|
|
151
|
+
partial: AssistantMessage;
|
|
152
|
+
} | {
|
|
153
|
+
type: 'text_start';
|
|
154
|
+
contentIndex: number;
|
|
155
|
+
partial: AssistantMessage;
|
|
156
|
+
} | {
|
|
157
|
+
type: 'text_delta';
|
|
158
|
+
contentIndex: number;
|
|
159
|
+
delta: string;
|
|
160
|
+
partial: AssistantMessage;
|
|
161
|
+
} | {
|
|
162
|
+
type: 'text_end';
|
|
163
|
+
contentIndex: number;
|
|
164
|
+
content: string;
|
|
165
|
+
partial: AssistantMessage;
|
|
166
|
+
} | {
|
|
167
|
+
type: 'thinking_start';
|
|
168
|
+
contentIndex: number;
|
|
169
|
+
partial: AssistantMessage;
|
|
170
|
+
} | {
|
|
171
|
+
type: 'thinking_delta';
|
|
172
|
+
contentIndex: number;
|
|
173
|
+
delta: string;
|
|
174
|
+
partial: AssistantMessage;
|
|
175
|
+
} | {
|
|
176
|
+
type: 'thinking_end';
|
|
177
|
+
contentIndex: number;
|
|
178
|
+
content: string;
|
|
179
|
+
partial: AssistantMessage;
|
|
180
|
+
} | {
|
|
181
|
+
type: 'toolcall_start';
|
|
182
|
+
contentIndex: number;
|
|
183
|
+
partial: AssistantMessage;
|
|
184
|
+
} | {
|
|
185
|
+
type: 'toolcall_delta';
|
|
186
|
+
contentIndex: number;
|
|
187
|
+
delta: string;
|
|
188
|
+
partial: AssistantMessage;
|
|
189
|
+
} | {
|
|
190
|
+
type: 'toolcall_end';
|
|
191
|
+
contentIndex: number;
|
|
192
|
+
toolCall: ToolCallContent;
|
|
193
|
+
partial: AssistantMessage;
|
|
194
|
+
} | {
|
|
195
|
+
type: 'done';
|
|
196
|
+
reason: Extract<StopReason, 'stop' | 'length' | 'toolUse'>;
|
|
197
|
+
message: AssistantMessage;
|
|
198
|
+
} | {
|
|
199
|
+
type: 'error';
|
|
200
|
+
reason: Extract<StopReason, 'error' | 'aborted'>;
|
|
201
|
+
error: AssistantMessage;
|
|
202
|
+
};
|
|
203
|
+
export interface ProviderAdapter<TOptions extends StreamOptions = StreamOptions> {
|
|
204
|
+
api: string;
|
|
205
|
+
provider: string;
|
|
206
|
+
createModel?: (modelId: string, overrides?: Partial<ModelDescriptor>) => ModelDescriptor;
|
|
207
|
+
listModels?: (options?: Pick<StreamOptions, 'apiKey' | 'headers'>) => Promise<Array<ModelDescriptor | string>>;
|
|
208
|
+
stream: (model: ModelDescriptor, context: Context, options?: TOptions) => AssistantMessageEventStream;
|
|
209
|
+
}
|
|
210
|
+
export interface LegacyChatMessage {
|
|
211
|
+
role: 'system' | 'user' | 'assistant';
|
|
212
|
+
content: string;
|
|
213
|
+
}
|
|
214
|
+
export interface LegacyGenerateInput {
|
|
215
|
+
model: string;
|
|
216
|
+
prompt?: string;
|
|
217
|
+
messages?: LegacyChatMessage[];
|
|
218
|
+
system?: string;
|
|
219
|
+
stream?: boolean;
|
|
220
|
+
temperature?: number;
|
|
221
|
+
maxTokens?: number;
|
|
222
|
+
}
|
|
223
|
+
export interface LegacyStreamingOptions {
|
|
224
|
+
onChunk?: (chunk: string) => void;
|
|
225
|
+
onComplete?: () => void;
|
|
226
|
+
onError?: (error: Error) => void;
|
|
227
|
+
onStateChange?: (state: string) => void;
|
|
228
|
+
}
|
|
229
|
+
export interface AssistantMessageEventStream extends AsyncIterable<AssistantMessageEvent> {
|
|
230
|
+
result(): Promise<AssistantMessage>;
|
|
231
|
+
}
|
package/types.js
ADDED