@quilltap/plugin-utils 1.0.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/CHANGELOG.md +32 -0
- package/README.md +167 -0
- package/dist/index.d.mts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +360 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +313 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logging/index.d.mts +109 -0
- package/dist/logging/index.d.ts +109 -0
- package/dist/logging/index.js +117 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/index.mjs +84 -0
- package/dist/logging/index.mjs.map +1 -0
- package/dist/tools/index.d.mts +236 -0
- package/dist/tools/index.d.ts +236 -0
- package/dist/tools/index.js +266 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/index.mjs +227 -0
- package/dist/tools/index.mjs.map +1 -0
- package/package.json +82 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to @quilltap/plugin-utils will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.0.0] - 2025-12-30
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Initial release of @quilltap/plugin-utils
|
|
10
|
+
- **Tool Parsing Utilities**
|
|
11
|
+
- `parseToolCalls()` - Parse tool calls with auto-detection or explicit format
|
|
12
|
+
- `parseOpenAIToolCalls()` - Parse OpenAI/Grok format tool calls
|
|
13
|
+
- `parseAnthropicToolCalls()` - Parse Anthropic format tool calls
|
|
14
|
+
- `parseGoogleToolCalls()` - Parse Google Gemini format tool calls
|
|
15
|
+
- `detectToolCallFormat()` - Detect the format of a response
|
|
16
|
+
- `hasToolCalls()` - Quick check if a response contains tool calls
|
|
17
|
+
|
|
18
|
+
- **Tool Conversion Utilities**
|
|
19
|
+
- `convertToAnthropicFormat()` - Convert universal tool to Anthropic format
|
|
20
|
+
- `convertToGoogleFormat()` - Convert universal tool to Google format
|
|
21
|
+
- `convertFromAnthropicFormat()` - Convert Anthropic tool to universal format
|
|
22
|
+
- `convertFromGoogleFormat()` - Convert Google tool to universal format
|
|
23
|
+
- `convertToolTo()` - Convert a tool to any supported format
|
|
24
|
+
- `convertToolsTo()` - Convert multiple tools to any format
|
|
25
|
+
- `applyDescriptionLimit()` - Truncate tool description if too long
|
|
26
|
+
|
|
27
|
+
- **Logger Bridge**
|
|
28
|
+
- `createPluginLogger()` - Create a logger that bridges to Quilltap core
|
|
29
|
+
- `hasCoreLogger()` - Check if running inside Quilltap
|
|
30
|
+
- `getLogLevelFromEnv()` - Get log level from environment variables
|
|
31
|
+
- Support for child loggers with context inheritance
|
|
32
|
+
- Automatic fallback to console logging when running standalone
|
package/README.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# @quilltap/plugin-utils
|
|
2
|
+
|
|
3
|
+
Utility functions for Quilltap plugin development. This package provides runtime utilities that complement the type definitions in `@quilltap/plugin-types`.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @quilltap/plugin-utils @quilltap/plugin-types
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### Tool Parsing
|
|
14
|
+
|
|
15
|
+
Parse tool calls from any LLM provider's response format into a standardized `ToolCallRequest[]`:
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { parseToolCalls, parseOpenAIToolCalls } from '@quilltap/plugin-utils';
|
|
19
|
+
|
|
20
|
+
// Auto-detect format
|
|
21
|
+
const toolCalls = parseToolCalls(response, 'auto');
|
|
22
|
+
|
|
23
|
+
// Or use provider-specific parsers
|
|
24
|
+
const openaiCalls = parseOpenAIToolCalls(response);
|
|
25
|
+
const anthropicCalls = parseAnthropicToolCalls(response);
|
|
26
|
+
const googleCalls = parseGoogleToolCalls(response);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Tool Format Conversion
|
|
30
|
+
|
|
31
|
+
Convert between OpenAI, Anthropic, and Google tool formats:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import {
|
|
35
|
+
convertToAnthropicFormat,
|
|
36
|
+
convertToGoogleFormat,
|
|
37
|
+
convertToolsTo
|
|
38
|
+
} from '@quilltap/plugin-utils';
|
|
39
|
+
|
|
40
|
+
// Convert a single tool
|
|
41
|
+
const anthropicTool = convertToAnthropicFormat(universalTool);
|
|
42
|
+
const googleTool = convertToGoogleFormat(universalTool);
|
|
43
|
+
|
|
44
|
+
// Convert multiple tools
|
|
45
|
+
const anthropicTools = convertToolsTo(tools, 'anthropic');
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Logger Bridge
|
|
49
|
+
|
|
50
|
+
Create a logger that integrates with Quilltap's core logging system when running inside the host application, or falls back to console logging when running standalone:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
import { createPluginLogger } from '@quilltap/plugin-utils';
|
|
54
|
+
|
|
55
|
+
// Create a logger for your plugin
|
|
56
|
+
const logger = createPluginLogger('qtap-plugin-my-provider');
|
|
57
|
+
|
|
58
|
+
// Use it like any standard logger
|
|
59
|
+
logger.debug('Initializing provider', { version: '1.0.0' });
|
|
60
|
+
logger.info('Provider ready');
|
|
61
|
+
logger.warn('Rate limit approaching', { remaining: 10 });
|
|
62
|
+
logger.error('API call failed', { endpoint: '/chat' }, error);
|
|
63
|
+
|
|
64
|
+
// Create child loggers with additional context
|
|
65
|
+
const childLogger = logger.child({ component: 'auth' });
|
|
66
|
+
childLogger.info('Validating API key');
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
When running inside Quilltap:
|
|
70
|
+
- Logs are routed to Quilltap's core logging system
|
|
71
|
+
- Logs appear in `logs/combined.log` and console
|
|
72
|
+
- Each log is tagged with `{ plugin: 'your-plugin-name', module: 'plugin' }`
|
|
73
|
+
|
|
74
|
+
When running standalone:
|
|
75
|
+
- Logs are written to console with `[plugin-name]` prefix
|
|
76
|
+
- Respects `LOG_LEVEL` or `QUILLTAP_LOG_LEVEL` environment variables
|
|
77
|
+
|
|
78
|
+
## API Reference
|
|
79
|
+
|
|
80
|
+
### Tool Parsing
|
|
81
|
+
|
|
82
|
+
| Function | Description |
|
|
83
|
+
|----------|-------------|
|
|
84
|
+
| `parseToolCalls(response, format)` | Parse tool calls with auto-detection or explicit format |
|
|
85
|
+
| `parseOpenAIToolCalls(response)` | Parse OpenAI/Grok format tool calls |
|
|
86
|
+
| `parseAnthropicToolCalls(response)` | Parse Anthropic format tool calls |
|
|
87
|
+
| `parseGoogleToolCalls(response)` | Parse Google Gemini format tool calls |
|
|
88
|
+
| `detectToolCallFormat(response)` | Detect the format of a response |
|
|
89
|
+
| `hasToolCalls(response)` | Check if a response contains tool calls |
|
|
90
|
+
|
|
91
|
+
### Tool Conversion
|
|
92
|
+
|
|
93
|
+
| Function | Description |
|
|
94
|
+
|----------|-------------|
|
|
95
|
+
| `convertToAnthropicFormat(tool)` | Convert universal tool to Anthropic format |
|
|
96
|
+
| `convertToGoogleFormat(tool)` | Convert universal tool to Google format |
|
|
97
|
+
| `convertFromAnthropicFormat(tool)` | Convert Anthropic tool to universal format |
|
|
98
|
+
| `convertFromGoogleFormat(tool)` | Convert Google tool to universal format |
|
|
99
|
+
| `convertToolTo(tool, target)` | Convert a tool to any supported format |
|
|
100
|
+
| `convertToolsTo(tools, target)` | Convert multiple tools to any format |
|
|
101
|
+
| `applyDescriptionLimit(tool, maxBytes)` | Truncate tool description if too long |
|
|
102
|
+
|
|
103
|
+
### Logging
|
|
104
|
+
|
|
105
|
+
| Function | Description |
|
|
106
|
+
|----------|-------------|
|
|
107
|
+
| `createPluginLogger(name, minLevel?)` | Create a plugin logger with core bridge |
|
|
108
|
+
| `hasCoreLogger()` | Check if running inside Quilltap |
|
|
109
|
+
| `getLogLevelFromEnv()` | Get log level from environment variables |
|
|
110
|
+
| `createConsoleLogger(prefix, minLevel?)` | Create a standalone console logger |
|
|
111
|
+
| `createNoopLogger()` | Create a no-op logger |
|
|
112
|
+
|
|
113
|
+
## Example: Complete Plugin Provider
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { createPluginLogger, parseOpenAIToolCalls } from '@quilltap/plugin-utils';
|
|
117
|
+
import type { LLMProvider, LLMParams, LLMResponse, ToolCallRequest } from '@quilltap/plugin-types';
|
|
118
|
+
import OpenAI from 'openai';
|
|
119
|
+
|
|
120
|
+
const logger = createPluginLogger('qtap-plugin-my-provider');
|
|
121
|
+
|
|
122
|
+
export class MyProvider implements LLMProvider {
|
|
123
|
+
private client: OpenAI;
|
|
124
|
+
|
|
125
|
+
constructor(apiKey: string) {
|
|
126
|
+
this.client = new OpenAI({ apiKey });
|
|
127
|
+
logger.debug('Provider initialized');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async sendMessage(params: LLMParams, apiKey: string): Promise<LLMResponse> {
|
|
131
|
+
logger.debug('Sending message', { model: params.model, messageCount: params.messages.length });
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const response = await this.client.chat.completions.create({
|
|
135
|
+
model: params.model,
|
|
136
|
+
messages: params.messages,
|
|
137
|
+
tools: params.tools,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Parse tool calls using the utility
|
|
141
|
+
const toolCalls = parseOpenAIToolCalls(response);
|
|
142
|
+
|
|
143
|
+
logger.info('Received response', {
|
|
144
|
+
hasToolCalls: toolCalls.length > 0,
|
|
145
|
+
tokens: response.usage?.total_tokens,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
content: response.choices[0].message.content || '',
|
|
150
|
+
toolCalls,
|
|
151
|
+
usage: {
|
|
152
|
+
promptTokens: response.usage?.prompt_tokens || 0,
|
|
153
|
+
completionTokens: response.usage?.completion_tokens || 0,
|
|
154
|
+
totalTokens: response.usage?.total_tokens || 0,
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
logger.error('Failed to send message', { model: params.model }, error as Error);
|
|
159
|
+
throw error;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
MIT - Foundry-9 LLC
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { AnthropicToolDefinition, GoogleToolDefinition, LogContext, LogLevel, OpenAIToolDefinition, PluginLogger, ToolCall, ToolCallRequest, ToolFormatOptions, ToolResult, UniversalTool, createConsoleLogger, createNoopLogger } from '@quilltap/plugin-types';
|
|
2
|
+
export { ToolCallFormat, ToolConvertTarget, applyDescriptionLimit, convertFromAnthropicFormat, convertFromGoogleFormat, convertToAnthropicFormat, convertToGoogleFormat, convertToolTo, convertToolsTo, detectToolCallFormat, hasToolCalls, parseAnthropicToolCalls, parseGoogleToolCalls, parseOpenAIToolCalls, parseToolCalls } from './tools/index.mjs';
|
|
3
|
+
export { PluginLoggerWithChild, __clearCoreLoggerFactory, __injectCoreLoggerFactory, createPluginLogger, getLogLevelFromEnv, hasCoreLogger } from './logging/index.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @quilltap/plugin-utils
|
|
7
|
+
*
|
|
8
|
+
* Utility functions for Quilltap plugin development.
|
|
9
|
+
*
|
|
10
|
+
* This package provides runtime utilities that complement the type definitions
|
|
11
|
+
* in @quilltap/plugin-types. It includes:
|
|
12
|
+
*
|
|
13
|
+
* - **Tool Parsing**: Parse tool calls from any LLM provider's response format
|
|
14
|
+
* - **Tool Conversion**: Convert between OpenAI, Anthropic, and Google tool formats
|
|
15
|
+
* - **Logger Bridge**: Logging that integrates with Quilltap's core or runs standalone
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
* @module @quilltap/plugin-utils
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Version of the plugin-utils package.
|
|
23
|
+
* Can be used at runtime to check compatibility.
|
|
24
|
+
*/
|
|
25
|
+
declare const PLUGIN_UTILS_VERSION = "1.0.0";
|
|
26
|
+
|
|
27
|
+
export { PLUGIN_UTILS_VERSION };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { AnthropicToolDefinition, GoogleToolDefinition, LogContext, LogLevel, OpenAIToolDefinition, PluginLogger, ToolCall, ToolCallRequest, ToolFormatOptions, ToolResult, UniversalTool, createConsoleLogger, createNoopLogger } from '@quilltap/plugin-types';
|
|
2
|
+
export { ToolCallFormat, ToolConvertTarget, applyDescriptionLimit, convertFromAnthropicFormat, convertFromGoogleFormat, convertToAnthropicFormat, convertToGoogleFormat, convertToolTo, convertToolsTo, detectToolCallFormat, hasToolCalls, parseAnthropicToolCalls, parseGoogleToolCalls, parseOpenAIToolCalls, parseToolCalls } from './tools/index.js';
|
|
3
|
+
export { PluginLoggerWithChild, __clearCoreLoggerFactory, __injectCoreLoggerFactory, createPluginLogger, getLogLevelFromEnv, hasCoreLogger } from './logging/index.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @quilltap/plugin-utils
|
|
7
|
+
*
|
|
8
|
+
* Utility functions for Quilltap plugin development.
|
|
9
|
+
*
|
|
10
|
+
* This package provides runtime utilities that complement the type definitions
|
|
11
|
+
* in @quilltap/plugin-types. It includes:
|
|
12
|
+
*
|
|
13
|
+
* - **Tool Parsing**: Parse tool calls from any LLM provider's response format
|
|
14
|
+
* - **Tool Conversion**: Convert between OpenAI, Anthropic, and Google tool formats
|
|
15
|
+
* - **Logger Bridge**: Logging that integrates with Quilltap's core or runs standalone
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
* @module @quilltap/plugin-utils
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Version of the plugin-utils package.
|
|
23
|
+
* Can be used at runtime to check compatibility.
|
|
24
|
+
*/
|
|
25
|
+
declare const PLUGIN_UTILS_VERSION = "1.0.0";
|
|
26
|
+
|
|
27
|
+
export { PLUGIN_UTILS_VERSION };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
PLUGIN_UTILS_VERSION: () => PLUGIN_UTILS_VERSION,
|
|
24
|
+
__clearCoreLoggerFactory: () => __clearCoreLoggerFactory,
|
|
25
|
+
__injectCoreLoggerFactory: () => __injectCoreLoggerFactory,
|
|
26
|
+
applyDescriptionLimit: () => applyDescriptionLimit,
|
|
27
|
+
convertFromAnthropicFormat: () => convertFromAnthropicFormat,
|
|
28
|
+
convertFromGoogleFormat: () => convertFromGoogleFormat,
|
|
29
|
+
convertToAnthropicFormat: () => convertToAnthropicFormat,
|
|
30
|
+
convertToGoogleFormat: () => convertToGoogleFormat,
|
|
31
|
+
convertToolTo: () => convertToolTo,
|
|
32
|
+
convertToolsTo: () => convertToolsTo,
|
|
33
|
+
createConsoleLogger: () => import_plugin_types.createConsoleLogger,
|
|
34
|
+
createNoopLogger: () => import_plugin_types.createNoopLogger,
|
|
35
|
+
createPluginLogger: () => createPluginLogger,
|
|
36
|
+
detectToolCallFormat: () => detectToolCallFormat,
|
|
37
|
+
getLogLevelFromEnv: () => getLogLevelFromEnv,
|
|
38
|
+
hasCoreLogger: () => hasCoreLogger,
|
|
39
|
+
hasToolCalls: () => hasToolCalls,
|
|
40
|
+
parseAnthropicToolCalls: () => parseAnthropicToolCalls,
|
|
41
|
+
parseGoogleToolCalls: () => parseGoogleToolCalls,
|
|
42
|
+
parseOpenAIToolCalls: () => parseOpenAIToolCalls,
|
|
43
|
+
parseToolCalls: () => parseToolCalls
|
|
44
|
+
});
|
|
45
|
+
module.exports = __toCommonJS(src_exports);
|
|
46
|
+
|
|
47
|
+
// src/tools/parsers.ts
|
|
48
|
+
function parseOpenAIToolCalls(response) {
|
|
49
|
+
const toolCalls = [];
|
|
50
|
+
try {
|
|
51
|
+
const resp = response;
|
|
52
|
+
let toolCallsArray = resp?.tool_calls;
|
|
53
|
+
if (!toolCallsArray) {
|
|
54
|
+
const choices = resp?.choices;
|
|
55
|
+
toolCallsArray = choices?.[0]?.message?.tool_calls;
|
|
56
|
+
}
|
|
57
|
+
if (toolCallsArray && Array.isArray(toolCallsArray) && toolCallsArray.length > 0) {
|
|
58
|
+
for (const toolCall of toolCallsArray) {
|
|
59
|
+
const tc = toolCall;
|
|
60
|
+
if (tc.type === "function" && tc.function) {
|
|
61
|
+
toolCalls.push({
|
|
62
|
+
name: tc.function.name,
|
|
63
|
+
arguments: JSON.parse(tc.function.arguments || "{}")
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("[plugin-utils] Error parsing OpenAI tool calls:", error);
|
|
70
|
+
}
|
|
71
|
+
return toolCalls;
|
|
72
|
+
}
|
|
73
|
+
function parseAnthropicToolCalls(response) {
|
|
74
|
+
const toolCalls = [];
|
|
75
|
+
try {
|
|
76
|
+
const resp = response;
|
|
77
|
+
if (!resp?.content || !Array.isArray(resp.content)) {
|
|
78
|
+
return toolCalls;
|
|
79
|
+
}
|
|
80
|
+
for (const block of resp.content) {
|
|
81
|
+
const b = block;
|
|
82
|
+
if (b.type === "tool_use" && b.name) {
|
|
83
|
+
toolCalls.push({
|
|
84
|
+
name: b.name,
|
|
85
|
+
arguments: b.input || {}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("[plugin-utils] Error parsing Anthropic tool calls:", error);
|
|
91
|
+
}
|
|
92
|
+
return toolCalls;
|
|
93
|
+
}
|
|
94
|
+
function parseGoogleToolCalls(response) {
|
|
95
|
+
const toolCalls = [];
|
|
96
|
+
try {
|
|
97
|
+
const resp = response;
|
|
98
|
+
const candidates = resp?.candidates;
|
|
99
|
+
const parts = candidates?.[0]?.content?.parts;
|
|
100
|
+
if (!parts || !Array.isArray(parts)) {
|
|
101
|
+
return toolCalls;
|
|
102
|
+
}
|
|
103
|
+
for (const part of parts) {
|
|
104
|
+
const p = part;
|
|
105
|
+
if (p.functionCall) {
|
|
106
|
+
toolCalls.push({
|
|
107
|
+
name: p.functionCall.name,
|
|
108
|
+
arguments: p.functionCall.args || {}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
} catch (error) {
|
|
113
|
+
console.error("[plugin-utils] Error parsing Google tool calls:", error);
|
|
114
|
+
}
|
|
115
|
+
return toolCalls;
|
|
116
|
+
}
|
|
117
|
+
function detectToolCallFormat(response) {
|
|
118
|
+
if (!response || typeof response !== "object") {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
const resp = response;
|
|
122
|
+
if (resp.tool_calls && Array.isArray(resp.tool_calls)) {
|
|
123
|
+
return "openai";
|
|
124
|
+
}
|
|
125
|
+
const choices = resp.choices;
|
|
126
|
+
if (choices?.[0]?.message?.tool_calls) {
|
|
127
|
+
return "openai";
|
|
128
|
+
}
|
|
129
|
+
if (resp.content && Array.isArray(resp.content)) {
|
|
130
|
+
const hasToolUse = resp.content.some(
|
|
131
|
+
(block) => block.type === "tool_use"
|
|
132
|
+
);
|
|
133
|
+
if (hasToolUse) {
|
|
134
|
+
return "anthropic";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const candidates = resp.candidates;
|
|
138
|
+
if (candidates?.[0]?.content?.parts) {
|
|
139
|
+
const hasFunctionCall = candidates[0].content.parts.some((part) => part.functionCall);
|
|
140
|
+
if (hasFunctionCall) {
|
|
141
|
+
return "google";
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
function parseToolCalls(response, format = "auto") {
|
|
147
|
+
let actualFormat = format;
|
|
148
|
+
if (format === "auto") {
|
|
149
|
+
actualFormat = detectToolCallFormat(response);
|
|
150
|
+
if (!actualFormat) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
switch (actualFormat) {
|
|
155
|
+
case "openai":
|
|
156
|
+
return parseOpenAIToolCalls(response);
|
|
157
|
+
case "anthropic":
|
|
158
|
+
return parseAnthropicToolCalls(response);
|
|
159
|
+
case "google":
|
|
160
|
+
return parseGoogleToolCalls(response);
|
|
161
|
+
default:
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function hasToolCalls(response) {
|
|
166
|
+
const format = detectToolCallFormat(response);
|
|
167
|
+
return format !== null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/tools/converters.ts
|
|
171
|
+
function convertToAnthropicFormat(tool) {
|
|
172
|
+
return {
|
|
173
|
+
name: tool.function.name,
|
|
174
|
+
description: tool.function.description,
|
|
175
|
+
input_schema: {
|
|
176
|
+
type: "object",
|
|
177
|
+
properties: tool.function.parameters.properties,
|
|
178
|
+
required: tool.function.parameters.required
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function convertToGoogleFormat(tool) {
|
|
183
|
+
return {
|
|
184
|
+
name: tool.function.name,
|
|
185
|
+
description: tool.function.description,
|
|
186
|
+
parameters: {
|
|
187
|
+
type: "object",
|
|
188
|
+
properties: tool.function.parameters.properties,
|
|
189
|
+
required: tool.function.parameters.required
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
function convertFromAnthropicFormat(tool) {
|
|
194
|
+
return {
|
|
195
|
+
type: "function",
|
|
196
|
+
function: {
|
|
197
|
+
name: tool.name,
|
|
198
|
+
description: tool.description ?? "",
|
|
199
|
+
parameters: {
|
|
200
|
+
type: "object",
|
|
201
|
+
properties: tool.input_schema.properties,
|
|
202
|
+
required: tool.input_schema.required ?? []
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function convertFromGoogleFormat(tool) {
|
|
208
|
+
return {
|
|
209
|
+
type: "function",
|
|
210
|
+
function: {
|
|
211
|
+
name: tool.name,
|
|
212
|
+
description: tool.description,
|
|
213
|
+
parameters: {
|
|
214
|
+
type: "object",
|
|
215
|
+
properties: tool.parameters.properties,
|
|
216
|
+
required: tool.parameters.required
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function applyDescriptionLimit(tool, maxBytes) {
|
|
222
|
+
if (!tool || !tool.description) {
|
|
223
|
+
return tool;
|
|
224
|
+
}
|
|
225
|
+
const warningText = " [Note: description truncated due to length limit]";
|
|
226
|
+
const maxDescBytes = maxBytes - Buffer.byteLength(warningText);
|
|
227
|
+
if (maxDescBytes <= 0) {
|
|
228
|
+
console.warn("[plugin-utils] Length limit too small for warning text:", maxBytes);
|
|
229
|
+
return tool;
|
|
230
|
+
}
|
|
231
|
+
const descBytes = Buffer.byteLength(tool.description);
|
|
232
|
+
if (descBytes > maxBytes) {
|
|
233
|
+
let truncated = tool.description;
|
|
234
|
+
while (Buffer.byteLength(truncated) > maxDescBytes && truncated.length > 0) {
|
|
235
|
+
truncated = truncated.slice(0, -1);
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
...tool,
|
|
239
|
+
description: truncated + warningText
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
return tool;
|
|
243
|
+
}
|
|
244
|
+
function convertToolTo(tool, target) {
|
|
245
|
+
switch (target) {
|
|
246
|
+
case "anthropic":
|
|
247
|
+
return convertToAnthropicFormat(tool);
|
|
248
|
+
case "google":
|
|
249
|
+
return convertToGoogleFormat(tool);
|
|
250
|
+
case "openai":
|
|
251
|
+
default:
|
|
252
|
+
return tool;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function convertToolsTo(tools, target) {
|
|
256
|
+
return tools.map((tool) => convertToolTo(tool, target));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/logging/plugin-logger.ts
|
|
260
|
+
function getCoreLoggerFactory() {
|
|
261
|
+
return globalThis.__quilltap_logger_factory ?? null;
|
|
262
|
+
}
|
|
263
|
+
function __injectCoreLoggerFactory(factory) {
|
|
264
|
+
globalThis.__quilltap_logger_factory = factory;
|
|
265
|
+
}
|
|
266
|
+
function __clearCoreLoggerFactory() {
|
|
267
|
+
globalThis.__quilltap_logger_factory = void 0;
|
|
268
|
+
}
|
|
269
|
+
function hasCoreLogger() {
|
|
270
|
+
return getCoreLoggerFactory() !== null;
|
|
271
|
+
}
|
|
272
|
+
function createConsoleLoggerWithChild(prefix, minLevel = "debug", baseContext = {}) {
|
|
273
|
+
const levels = ["debug", "info", "warn", "error"];
|
|
274
|
+
const shouldLog = (level) => levels.indexOf(level) >= levels.indexOf(minLevel);
|
|
275
|
+
const formatContext = (context) => {
|
|
276
|
+
const merged = { ...baseContext, ...context };
|
|
277
|
+
const entries = Object.entries(merged).filter(([key]) => key !== "context").map(([key, value]) => `${key}=${JSON.stringify(value)}`).join(" ");
|
|
278
|
+
return entries ? ` ${entries}` : "";
|
|
279
|
+
};
|
|
280
|
+
const logger = {
|
|
281
|
+
debug: (message, context) => {
|
|
282
|
+
if (shouldLog("debug")) {
|
|
283
|
+
console.debug(`[${prefix}] ${message}${formatContext(context)}`);
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
info: (message, context) => {
|
|
287
|
+
if (shouldLog("info")) {
|
|
288
|
+
console.info(`[${prefix}] ${message}${formatContext(context)}`);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
warn: (message, context) => {
|
|
292
|
+
if (shouldLog("warn")) {
|
|
293
|
+
console.warn(`[${prefix}] ${message}${formatContext(context)}`);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
error: (message, context, error) => {
|
|
297
|
+
if (shouldLog("error")) {
|
|
298
|
+
console.error(
|
|
299
|
+
`[${prefix}] ${message}${formatContext(context)}`,
|
|
300
|
+
error ? `
|
|
301
|
+
${error.stack || error.message}` : ""
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
child: (additionalContext) => {
|
|
306
|
+
return createConsoleLoggerWithChild(prefix, minLevel, {
|
|
307
|
+
...baseContext,
|
|
308
|
+
...additionalContext
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
return logger;
|
|
313
|
+
}
|
|
314
|
+
function createPluginLogger(pluginName, minLevel = "debug") {
|
|
315
|
+
const coreFactory = getCoreLoggerFactory();
|
|
316
|
+
if (coreFactory) {
|
|
317
|
+
return coreFactory(pluginName);
|
|
318
|
+
}
|
|
319
|
+
return createConsoleLoggerWithChild(pluginName, minLevel);
|
|
320
|
+
}
|
|
321
|
+
function getLogLevelFromEnv() {
|
|
322
|
+
if (typeof process !== "undefined" && process.env) {
|
|
323
|
+
const envLevel = process.env.LOG_LEVEL || process.env.QUILTTAP_LOG_LEVEL;
|
|
324
|
+
if (envLevel && ["debug", "info", "warn", "error"].includes(envLevel)) {
|
|
325
|
+
return envLevel;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return "info";
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/logging/index.ts
|
|
332
|
+
var import_plugin_types = require("@quilltap/plugin-types");
|
|
333
|
+
|
|
334
|
+
// src/index.ts
|
|
335
|
+
var PLUGIN_UTILS_VERSION = "1.0.0";
|
|
336
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
337
|
+
0 && (module.exports = {
|
|
338
|
+
PLUGIN_UTILS_VERSION,
|
|
339
|
+
__clearCoreLoggerFactory,
|
|
340
|
+
__injectCoreLoggerFactory,
|
|
341
|
+
applyDescriptionLimit,
|
|
342
|
+
convertFromAnthropicFormat,
|
|
343
|
+
convertFromGoogleFormat,
|
|
344
|
+
convertToAnthropicFormat,
|
|
345
|
+
convertToGoogleFormat,
|
|
346
|
+
convertToolTo,
|
|
347
|
+
convertToolsTo,
|
|
348
|
+
createConsoleLogger,
|
|
349
|
+
createNoopLogger,
|
|
350
|
+
createPluginLogger,
|
|
351
|
+
detectToolCallFormat,
|
|
352
|
+
getLogLevelFromEnv,
|
|
353
|
+
hasCoreLogger,
|
|
354
|
+
hasToolCalls,
|
|
355
|
+
parseAnthropicToolCalls,
|
|
356
|
+
parseGoogleToolCalls,
|
|
357
|
+
parseOpenAIToolCalls,
|
|
358
|
+
parseToolCalls
|
|
359
|
+
});
|
|
360
|
+
//# sourceMappingURL=index.js.map
|