signalloomai 0.1.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 +119 -0
- package/dist/index.cjs +184 -0
- package/dist/index.d.cts +95 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.js +157 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Signal Loom AI — LangChain Integration
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>LoomLens AI</strong> — Token cost estimation for AI pipelines.<br>
|
|
5
|
+
Compare GPT-4o, Claude Sonnet 4, Gemini 2.5, DeepSeek, and more. Before you run.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p align="center">
|
|
9
|
+
<a href="https://signalloomai.com">Website</a> ·
|
|
10
|
+
<a href="https://signalloomai.com/docs">API Docs</a> ·
|
|
11
|
+
<a href="https://signalloomai.com/prompt-integrity.html">Prompt Integrity</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install signalloomai
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Requires Node.js 18+.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { LoomLensTool } from 'signalloomai';
|
|
30
|
+
|
|
31
|
+
// Initialize with your API key
|
|
32
|
+
const tool = new LoomLensTool({ apiKey: process.env.SIGNALLOOM_API_KEY });
|
|
33
|
+
|
|
34
|
+
// Get a cost estimate
|
|
35
|
+
const result = await tool.estimate({
|
|
36
|
+
job_description: 'Customer support agent with 5 sub-agents handling billing and shipping',
|
|
37
|
+
num_agents: 5,
|
|
38
|
+
estimated_runtime_minutes: 20,
|
|
39
|
+
complexity: 'standard',
|
|
40
|
+
target_models: [
|
|
41
|
+
'openai/gpt-4o',
|
|
42
|
+
'anthropic/claude-sonnet-4-20250514',
|
|
43
|
+
'google/gemini-2.5-flash',
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log(`Cheapest model: ${result.cheapest_model}`);
|
|
48
|
+
console.log(`Savings vs most expensive: $${result.savings_vs_expensive}`);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Use with LangChain Agents
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { LoomLensTool } from 'signalloomai';
|
|
57
|
+
import { ChatOpenAI } from '@langchain/openai';
|
|
58
|
+
import { createReactAgent } from 'langchain-agents';
|
|
59
|
+
|
|
60
|
+
// Initialize
|
|
61
|
+
const loomLensTool = new LoomLensTool({ apiKey: process.env.SIGNALLOOM_API_KEY });
|
|
62
|
+
const llm = new ChatOpenAI({ modelName: 'gpt-4o', temperature: 0 });
|
|
63
|
+
|
|
64
|
+
// Create agent with LoomLens as a tool
|
|
65
|
+
const agent = createReactAgent({
|
|
66
|
+
llm,
|
|
67
|
+
tools: [loomLensTool.toLangChainTool()],
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Run
|
|
71
|
+
const response = await agent.invoke({
|
|
72
|
+
input: 'Compare the cost of running a 10-agent research pipeline on GPT-4o vs Claude Sonnet 4',
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## API Key
|
|
79
|
+
|
|
80
|
+
Get your API key at **[signalloomai.com](https://signalloomai.com)**.
|
|
81
|
+
|
|
82
|
+
Set it as an environment variable:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
export SIGNALLOOM_API_KEY=sk_...
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Or pass it directly:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const tool = new LoomLensTool({ apiKey: 'sk_your_key_here' });
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Prompt Integrity
|
|
97
|
+
|
|
98
|
+
**LoomLens AI does NOT log prompts or job descriptions.**
|
|
99
|
+
|
|
100
|
+
We estimate cost based on token counts and model pricing — not by reading your content. See our full [Prompt Integrity Policy](https://signalloomai.com/prompt-integrity.html).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Available Models
|
|
105
|
+
|
|
106
|
+
| Provider | Model |
|
|
107
|
+
|----------|-------|
|
|
108
|
+
| OpenAI | `gpt-4o`, `gpt-4o-mini` |
|
|
109
|
+
| Anthropic | `claude-sonnet-4-20250514`, `claude-opus-4-6` |
|
|
110
|
+
| Google | `gemini-2.5-flash`, `gemini-2.5-pro` |
|
|
111
|
+
| DeepSeek | `deepseek-chat-v3` |
|
|
112
|
+
| xAI | `grok-3` |
|
|
113
|
+
| MiniMax | `MiniMax-M2.7` |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT · [signalloomai.com/terms.html](https://signalloomai.com/terms.html)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
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 index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
LoomLensTool: () => LoomLensTool,
|
|
24
|
+
SIGNALLOOM_PACKAGE_INFO: () => SIGNALLOOM_PACKAGE_INFO,
|
|
25
|
+
createLoomLensTool: () => createLoomLensTool
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(index_exports);
|
|
28
|
+
var import_tools = require("@langchain/core/tools");
|
|
29
|
+
var BASE_URL = "https://api.signalloomai.com";
|
|
30
|
+
var TOOL_NAME = "loomlens_ai_estimate";
|
|
31
|
+
var TOOL_DESCRIPTION = `
|
|
32
|
+
**LoomLens AI \u2014 Token Cost Estimator**
|
|
33
|
+
|
|
34
|
+
Use this tool to compare AI pipeline costs across different models BEFORE you run them.
|
|
35
|
+
No more billing surprises. Estimate your cost per job across GPT-4o, Claude Sonnet 4,
|
|
36
|
+
Claude Opus 4, Gemini 2.5 Flash, DeepSeek Chat v3, Grok 3, and more.
|
|
37
|
+
|
|
38
|
+
Input:
|
|
39
|
+
- job_description: What the pipeline does (natural language)
|
|
40
|
+
- target_models: List of model IDs to compare
|
|
41
|
+
- num_agents: Number of concurrent agents (default: 1)
|
|
42
|
+
- estimated_runtime_minutes: Expected runtime in minutes (default: 5)
|
|
43
|
+
- complexity: trivial | simple | standard | complex | extreme (default: standard)
|
|
44
|
+
|
|
45
|
+
Output:
|
|
46
|
+
- Cost estimate (low/mid/high) for each model
|
|
47
|
+
- Cheapest model recommendation
|
|
48
|
+
- Potential savings vs most expensive option
|
|
49
|
+
|
|
50
|
+
**Prompt Integrity: This tool does NOT log prompts or job descriptions.**
|
|
51
|
+
See: https://signalloomai.com/prompt-integrity.html
|
|
52
|
+
|
|
53
|
+
Available models:
|
|
54
|
+
- openai/gpt-4o
|
|
55
|
+
- openai/gpt-4o-mini
|
|
56
|
+
- anthropic/claude-sonnet-4-20250514
|
|
57
|
+
- anthropic/claude-opus-4-6
|
|
58
|
+
- google/gemini-2.5-flash
|
|
59
|
+
- google/gemini-2.5-pro
|
|
60
|
+
- deepseek/deepseek-chat-v3
|
|
61
|
+
- xai/grok-3
|
|
62
|
+
- minimax/MiniMax-M2.7
|
|
63
|
+
`.trim();
|
|
64
|
+
var LoomLensTool = class {
|
|
65
|
+
constructor(config = {}) {
|
|
66
|
+
this.name = TOOL_NAME;
|
|
67
|
+
this.description = TOOL_DESCRIPTION;
|
|
68
|
+
this.apiKey = config.apiKey || process.env.SIGNALLOOM_API_KEY || process.env.SIGNALLOOM_API_KEY || "";
|
|
69
|
+
this.baseUrl = config.baseUrl || BASE_URL;
|
|
70
|
+
if (!this.apiKey) {
|
|
71
|
+
console.warn(
|
|
72
|
+
"[LoomLensTool] No API key provided. Set SIGNALLOOM_API_KEY env var or pass apiKey."
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Estimate token cost for an AI pipeline.
|
|
78
|
+
*/
|
|
79
|
+
async estimate(input) {
|
|
80
|
+
if (!this.apiKey) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"Signal Loom API key required. Set SIGNALLOOM_API_KEY env var or pass apiKey."
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const payload = {
|
|
86
|
+
job_description: input.job_description,
|
|
87
|
+
num_agents: input.num_agents ?? 1,
|
|
88
|
+
estimated_runtime_minutes: input.estimated_runtime_minutes ?? 5,
|
|
89
|
+
complexity: input.complexity ?? "standard",
|
|
90
|
+
target_models: input.target_models,
|
|
91
|
+
include_postmortem: input.include_postmortem ?? false
|
|
92
|
+
};
|
|
93
|
+
const response = await fetch(`${this.baseUrl}/v1/estimate`, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: {
|
|
96
|
+
"Content-Type": "application/json",
|
|
97
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
98
|
+
},
|
|
99
|
+
body: JSON.stringify(payload)
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
const error = await response.json().catch(() => ({ detail: response.statusText }));
|
|
103
|
+
throw new Error(`LoomLens API error ${response.status}: ${error?.detail ?? response.statusText}`);
|
|
104
|
+
}
|
|
105
|
+
return response.json();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Estimate and return a human-readable summary string.
|
|
109
|
+
*/
|
|
110
|
+
async estimateSummary(input) {
|
|
111
|
+
const result = await this.estimate(input);
|
|
112
|
+
const { cheapest_model, most_expensive_model, savings_vs_expensive, models, billing } = result;
|
|
113
|
+
const lines = [
|
|
114
|
+
`## LoomLens AI Estimate`,
|
|
115
|
+
``,
|
|
116
|
+
`**Cheapest:** ${cheapest_model}`,
|
|
117
|
+
`**Most expensive:** ${most_expensive_model}`,
|
|
118
|
+
`**Savings (cheapest vs most expensive):** $${savings_vs_expensive.toFixed(6)} per job`,
|
|
119
|
+
``,
|
|
120
|
+
`### Cost Comparison`,
|
|
121
|
+
``,
|
|
122
|
+
...models.map(
|
|
123
|
+
(m) => ` ${m.model}: **$${m.estimated_cost_mid.toFixed(6)}/job** (range: $${m.estimated_cost_low.toFixed(6)}\u2013$${m.estimated_cost_high.toFixed(6)})${m.model === cheapest_model ? " \u2190 CHEAPEST" : ""}${m.model === most_expensive_model ? " \u2190 MOST EXPENSIVE" : ""}`
|
|
124
|
+
),
|
|
125
|
+
``,
|
|
126
|
+
`**Estimate call cost:** $${billing.call_cost_usd.toFixed(6)}`,
|
|
127
|
+
`**Quota remaining:** ${billing.remaining_this_month} calls this month`,
|
|
128
|
+
``,
|
|
129
|
+
`*Powered by LoomLens AI \u2014 https://signalloomai.com/token-estimator.html*`
|
|
130
|
+
];
|
|
131
|
+
return lines.join("\n");
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Return a LangChain-compatible BaseTool instance.
|
|
135
|
+
*
|
|
136
|
+
* Requires langchain as a peer dependency.
|
|
137
|
+
*/
|
|
138
|
+
toLangChainTool() {
|
|
139
|
+
const self = this;
|
|
140
|
+
const ToolClass = import_tools.Tool;
|
|
141
|
+
return new ToolClass({
|
|
142
|
+
name: self.name,
|
|
143
|
+
description: self.description,
|
|
144
|
+
returnDirect: false,
|
|
145
|
+
async call(input) {
|
|
146
|
+
let parsed;
|
|
147
|
+
if (typeof input === "string") {
|
|
148
|
+
try {
|
|
149
|
+
parsed = JSON.parse(input);
|
|
150
|
+
} catch {
|
|
151
|
+
throw new Error(
|
|
152
|
+
`LoomLensTool requires JSON input. Received: ${input.slice(0, 100)}`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
parsed = input;
|
|
157
|
+
}
|
|
158
|
+
if (!parsed.job_description || !parsed.target_models?.length) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
"LoomLensTool requires job_description and target_models. Example: { job_description: 'Research agent', target_models: ['openai/gpt-4o'] }"
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
return self.estimateSummary(parsed);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
function createLoomLensTool(config) {
|
|
169
|
+
return new LoomLensTool(config);
|
|
170
|
+
}
|
|
171
|
+
var SIGNALLOOM_PACKAGE_INFO = {
|
|
172
|
+
name: "signalloomai",
|
|
173
|
+
version: "1.0.0",
|
|
174
|
+
homepage: "https://signalloomai.com",
|
|
175
|
+
docs: "https://signalloomai.com/docs",
|
|
176
|
+
promptIntegrity: "https://signalloomai.com/prompt-integrity.html"
|
|
177
|
+
/** Prompt: This tool does NOT log prompts or job descriptions. */
|
|
178
|
+
};
|
|
179
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
180
|
+
0 && (module.exports = {
|
|
181
|
+
LoomLensTool,
|
|
182
|
+
SIGNALLOOM_PACKAGE_INFO,
|
|
183
|
+
createLoomLensTool
|
|
184
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Tool } from '@langchain/core/tools';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Signal Loom AI — LangChain Tool Wrapper
|
|
5
|
+
* ========================================
|
|
6
|
+
* Exposes LoomLens AI as a LangChain-compatible tool.
|
|
7
|
+
*
|
|
8
|
+
* Install:
|
|
9
|
+
* npm install signalloomai
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* import { LoomLensTool } from 'signalloomai';
|
|
13
|
+
*
|
|
14
|
+
* const tool = new LoomLensTool({ apiKey: 'sk_...' });
|
|
15
|
+
*
|
|
16
|
+
* // Use as a LangChain tool
|
|
17
|
+
* const model = new ChatOpenAI({ modelName: 'gpt-4o' });
|
|
18
|
+
* const agent = createReactAgent({ llm: model, tools: [tool.toLangChainTool()] });
|
|
19
|
+
*
|
|
20
|
+
* const result = await agent.invoke({
|
|
21
|
+
* input: 'Compare the cost of running a 5-agent pipeline on GPT-4o vs Claude Sonnet 4'
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* Docs: https://signalloomai.com/docs
|
|
25
|
+
* Prompt Integrity: https://signalloomai.com/prompt-integrity.html
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
interface LoomLensEstimateInput {
|
|
29
|
+
/** Natural language description of the AI pipeline job */
|
|
30
|
+
job_description: string;
|
|
31
|
+
/** List of model IDs to compare */
|
|
32
|
+
target_models: string[];
|
|
33
|
+
/** Number of concurrent agents (default: 1) */
|
|
34
|
+
num_agents?: number;
|
|
35
|
+
/** Estimated runtime in minutes (default: 5.0) */
|
|
36
|
+
estimated_runtime_minutes?: number;
|
|
37
|
+
/** Task complexity (default: 'standard') */
|
|
38
|
+
complexity?: "trivial" | "simple" | "standard" | "complex" | "extreme";
|
|
39
|
+
/** Include detailed cost breakdown (default: false) */
|
|
40
|
+
include_postmortem?: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface LoomLensEstimateResult {
|
|
43
|
+
cheapest_model: string;
|
|
44
|
+
most_expensive_model: string;
|
|
45
|
+
savings_vs_expensive: number;
|
|
46
|
+
models: Array<{
|
|
47
|
+
model: string;
|
|
48
|
+
estimated_cost_mid: number;
|
|
49
|
+
estimated_cost_low: number;
|
|
50
|
+
estimated_cost_high: number;
|
|
51
|
+
}>;
|
|
52
|
+
billing: {
|
|
53
|
+
tier: string;
|
|
54
|
+
call_cost_usd: number;
|
|
55
|
+
used_this_month: number;
|
|
56
|
+
remaining_this_month: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
interface LoomLensToolConfig {
|
|
60
|
+
/** Your Signal Loom API key. Falls back to SIGNALLOOM_API_KEY env var. */
|
|
61
|
+
apiKey?: string;
|
|
62
|
+
/** API base URL. Defaults to production. */
|
|
63
|
+
baseUrl?: string;
|
|
64
|
+
}
|
|
65
|
+
declare class LoomLensTool {
|
|
66
|
+
apiKey: string;
|
|
67
|
+
baseUrl: string;
|
|
68
|
+
readonly name = "loomlens_ai_estimate";
|
|
69
|
+
readonly description: string;
|
|
70
|
+
constructor(config?: LoomLensToolConfig);
|
|
71
|
+
/**
|
|
72
|
+
* Estimate token cost for an AI pipeline.
|
|
73
|
+
*/
|
|
74
|
+
estimate(input: LoomLensEstimateInput): Promise<LoomLensEstimateResult>;
|
|
75
|
+
/**
|
|
76
|
+
* Estimate and return a human-readable summary string.
|
|
77
|
+
*/
|
|
78
|
+
estimateSummary(input: LoomLensEstimateInput): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Return a LangChain-compatible BaseTool instance.
|
|
81
|
+
*
|
|
82
|
+
* Requires langchain as a peer dependency.
|
|
83
|
+
*/
|
|
84
|
+
toLangChainTool(): Tool;
|
|
85
|
+
}
|
|
86
|
+
declare function createLoomLensTool(config?: LoomLensToolConfig): LoomLensTool;
|
|
87
|
+
declare const SIGNALLOOM_PACKAGE_INFO: {
|
|
88
|
+
name: string;
|
|
89
|
+
version: string;
|
|
90
|
+
homepage: string;
|
|
91
|
+
docs: string;
|
|
92
|
+
promptIntegrity: string;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { type LoomLensEstimateInput, type LoomLensEstimateResult, LoomLensTool, type LoomLensToolConfig, SIGNALLOOM_PACKAGE_INFO, createLoomLensTool };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Tool } from '@langchain/core/tools';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Signal Loom AI — LangChain Tool Wrapper
|
|
5
|
+
* ========================================
|
|
6
|
+
* Exposes LoomLens AI as a LangChain-compatible tool.
|
|
7
|
+
*
|
|
8
|
+
* Install:
|
|
9
|
+
* npm install signalloomai
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* import { LoomLensTool } from 'signalloomai';
|
|
13
|
+
*
|
|
14
|
+
* const tool = new LoomLensTool({ apiKey: 'sk_...' });
|
|
15
|
+
*
|
|
16
|
+
* // Use as a LangChain tool
|
|
17
|
+
* const model = new ChatOpenAI({ modelName: 'gpt-4o' });
|
|
18
|
+
* const agent = createReactAgent({ llm: model, tools: [tool.toLangChainTool()] });
|
|
19
|
+
*
|
|
20
|
+
* const result = await agent.invoke({
|
|
21
|
+
* input: 'Compare the cost of running a 5-agent pipeline on GPT-4o vs Claude Sonnet 4'
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* Docs: https://signalloomai.com/docs
|
|
25
|
+
* Prompt Integrity: https://signalloomai.com/prompt-integrity.html
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
interface LoomLensEstimateInput {
|
|
29
|
+
/** Natural language description of the AI pipeline job */
|
|
30
|
+
job_description: string;
|
|
31
|
+
/** List of model IDs to compare */
|
|
32
|
+
target_models: string[];
|
|
33
|
+
/** Number of concurrent agents (default: 1) */
|
|
34
|
+
num_agents?: number;
|
|
35
|
+
/** Estimated runtime in minutes (default: 5.0) */
|
|
36
|
+
estimated_runtime_minutes?: number;
|
|
37
|
+
/** Task complexity (default: 'standard') */
|
|
38
|
+
complexity?: "trivial" | "simple" | "standard" | "complex" | "extreme";
|
|
39
|
+
/** Include detailed cost breakdown (default: false) */
|
|
40
|
+
include_postmortem?: boolean;
|
|
41
|
+
}
|
|
42
|
+
interface LoomLensEstimateResult {
|
|
43
|
+
cheapest_model: string;
|
|
44
|
+
most_expensive_model: string;
|
|
45
|
+
savings_vs_expensive: number;
|
|
46
|
+
models: Array<{
|
|
47
|
+
model: string;
|
|
48
|
+
estimated_cost_mid: number;
|
|
49
|
+
estimated_cost_low: number;
|
|
50
|
+
estimated_cost_high: number;
|
|
51
|
+
}>;
|
|
52
|
+
billing: {
|
|
53
|
+
tier: string;
|
|
54
|
+
call_cost_usd: number;
|
|
55
|
+
used_this_month: number;
|
|
56
|
+
remaining_this_month: number;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
interface LoomLensToolConfig {
|
|
60
|
+
/** Your Signal Loom API key. Falls back to SIGNALLOOM_API_KEY env var. */
|
|
61
|
+
apiKey?: string;
|
|
62
|
+
/** API base URL. Defaults to production. */
|
|
63
|
+
baseUrl?: string;
|
|
64
|
+
}
|
|
65
|
+
declare class LoomLensTool {
|
|
66
|
+
apiKey: string;
|
|
67
|
+
baseUrl: string;
|
|
68
|
+
readonly name = "loomlens_ai_estimate";
|
|
69
|
+
readonly description: string;
|
|
70
|
+
constructor(config?: LoomLensToolConfig);
|
|
71
|
+
/**
|
|
72
|
+
* Estimate token cost for an AI pipeline.
|
|
73
|
+
*/
|
|
74
|
+
estimate(input: LoomLensEstimateInput): Promise<LoomLensEstimateResult>;
|
|
75
|
+
/**
|
|
76
|
+
* Estimate and return a human-readable summary string.
|
|
77
|
+
*/
|
|
78
|
+
estimateSummary(input: LoomLensEstimateInput): Promise<string>;
|
|
79
|
+
/**
|
|
80
|
+
* Return a LangChain-compatible BaseTool instance.
|
|
81
|
+
*
|
|
82
|
+
* Requires langchain as a peer dependency.
|
|
83
|
+
*/
|
|
84
|
+
toLangChainTool(): Tool;
|
|
85
|
+
}
|
|
86
|
+
declare function createLoomLensTool(config?: LoomLensToolConfig): LoomLensTool;
|
|
87
|
+
declare const SIGNALLOOM_PACKAGE_INFO: {
|
|
88
|
+
name: string;
|
|
89
|
+
version: string;
|
|
90
|
+
homepage: string;
|
|
91
|
+
docs: string;
|
|
92
|
+
promptIntegrity: string;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export { type LoomLensEstimateInput, type LoomLensEstimateResult, LoomLensTool, type LoomLensToolConfig, SIGNALLOOM_PACKAGE_INFO, createLoomLensTool };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { Tool } from "@langchain/core/tools";
|
|
3
|
+
var BASE_URL = "https://api.signalloomai.com";
|
|
4
|
+
var TOOL_NAME = "loomlens_ai_estimate";
|
|
5
|
+
var TOOL_DESCRIPTION = `
|
|
6
|
+
**LoomLens AI \u2014 Token Cost Estimator**
|
|
7
|
+
|
|
8
|
+
Use this tool to compare AI pipeline costs across different models BEFORE you run them.
|
|
9
|
+
No more billing surprises. Estimate your cost per job across GPT-4o, Claude Sonnet 4,
|
|
10
|
+
Claude Opus 4, Gemini 2.5 Flash, DeepSeek Chat v3, Grok 3, and more.
|
|
11
|
+
|
|
12
|
+
Input:
|
|
13
|
+
- job_description: What the pipeline does (natural language)
|
|
14
|
+
- target_models: List of model IDs to compare
|
|
15
|
+
- num_agents: Number of concurrent agents (default: 1)
|
|
16
|
+
- estimated_runtime_minutes: Expected runtime in minutes (default: 5)
|
|
17
|
+
- complexity: trivial | simple | standard | complex | extreme (default: standard)
|
|
18
|
+
|
|
19
|
+
Output:
|
|
20
|
+
- Cost estimate (low/mid/high) for each model
|
|
21
|
+
- Cheapest model recommendation
|
|
22
|
+
- Potential savings vs most expensive option
|
|
23
|
+
|
|
24
|
+
**Prompt Integrity: This tool does NOT log prompts or job descriptions.**
|
|
25
|
+
See: https://signalloomai.com/prompt-integrity.html
|
|
26
|
+
|
|
27
|
+
Available models:
|
|
28
|
+
- openai/gpt-4o
|
|
29
|
+
- openai/gpt-4o-mini
|
|
30
|
+
- anthropic/claude-sonnet-4-20250514
|
|
31
|
+
- anthropic/claude-opus-4-6
|
|
32
|
+
- google/gemini-2.5-flash
|
|
33
|
+
- google/gemini-2.5-pro
|
|
34
|
+
- deepseek/deepseek-chat-v3
|
|
35
|
+
- xai/grok-3
|
|
36
|
+
- minimax/MiniMax-M2.7
|
|
37
|
+
`.trim();
|
|
38
|
+
var LoomLensTool = class {
|
|
39
|
+
constructor(config = {}) {
|
|
40
|
+
this.name = TOOL_NAME;
|
|
41
|
+
this.description = TOOL_DESCRIPTION;
|
|
42
|
+
this.apiKey = config.apiKey || process.env.SIGNALLOOM_API_KEY || process.env.SIGNALLOOM_API_KEY || "";
|
|
43
|
+
this.baseUrl = config.baseUrl || BASE_URL;
|
|
44
|
+
if (!this.apiKey) {
|
|
45
|
+
console.warn(
|
|
46
|
+
"[LoomLensTool] No API key provided. Set SIGNALLOOM_API_KEY env var or pass apiKey."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Estimate token cost for an AI pipeline.
|
|
52
|
+
*/
|
|
53
|
+
async estimate(input) {
|
|
54
|
+
if (!this.apiKey) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Signal Loom API key required. Set SIGNALLOOM_API_KEY env var or pass apiKey."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const payload = {
|
|
60
|
+
job_description: input.job_description,
|
|
61
|
+
num_agents: input.num_agents ?? 1,
|
|
62
|
+
estimated_runtime_minutes: input.estimated_runtime_minutes ?? 5,
|
|
63
|
+
complexity: input.complexity ?? "standard",
|
|
64
|
+
target_models: input.target_models,
|
|
65
|
+
include_postmortem: input.include_postmortem ?? false
|
|
66
|
+
};
|
|
67
|
+
const response = await fetch(`${this.baseUrl}/v1/estimate`, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
72
|
+
},
|
|
73
|
+
body: JSON.stringify(payload)
|
|
74
|
+
});
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
const error = await response.json().catch(() => ({ detail: response.statusText }));
|
|
77
|
+
throw new Error(`LoomLens API error ${response.status}: ${error?.detail ?? response.statusText}`);
|
|
78
|
+
}
|
|
79
|
+
return response.json();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Estimate and return a human-readable summary string.
|
|
83
|
+
*/
|
|
84
|
+
async estimateSummary(input) {
|
|
85
|
+
const result = await this.estimate(input);
|
|
86
|
+
const { cheapest_model, most_expensive_model, savings_vs_expensive, models, billing } = result;
|
|
87
|
+
const lines = [
|
|
88
|
+
`## LoomLens AI Estimate`,
|
|
89
|
+
``,
|
|
90
|
+
`**Cheapest:** ${cheapest_model}`,
|
|
91
|
+
`**Most expensive:** ${most_expensive_model}`,
|
|
92
|
+
`**Savings (cheapest vs most expensive):** $${savings_vs_expensive.toFixed(6)} per job`,
|
|
93
|
+
``,
|
|
94
|
+
`### Cost Comparison`,
|
|
95
|
+
``,
|
|
96
|
+
...models.map(
|
|
97
|
+
(m) => ` ${m.model}: **$${m.estimated_cost_mid.toFixed(6)}/job** (range: $${m.estimated_cost_low.toFixed(6)}\u2013$${m.estimated_cost_high.toFixed(6)})${m.model === cheapest_model ? " \u2190 CHEAPEST" : ""}${m.model === most_expensive_model ? " \u2190 MOST EXPENSIVE" : ""}`
|
|
98
|
+
),
|
|
99
|
+
``,
|
|
100
|
+
`**Estimate call cost:** $${billing.call_cost_usd.toFixed(6)}`,
|
|
101
|
+
`**Quota remaining:** ${billing.remaining_this_month} calls this month`,
|
|
102
|
+
``,
|
|
103
|
+
`*Powered by LoomLens AI \u2014 https://signalloomai.com/token-estimator.html*`
|
|
104
|
+
];
|
|
105
|
+
return lines.join("\n");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Return a LangChain-compatible BaseTool instance.
|
|
109
|
+
*
|
|
110
|
+
* Requires langchain as a peer dependency.
|
|
111
|
+
*/
|
|
112
|
+
toLangChainTool() {
|
|
113
|
+
const self = this;
|
|
114
|
+
const ToolClass = Tool;
|
|
115
|
+
return new ToolClass({
|
|
116
|
+
name: self.name,
|
|
117
|
+
description: self.description,
|
|
118
|
+
returnDirect: false,
|
|
119
|
+
async call(input) {
|
|
120
|
+
let parsed;
|
|
121
|
+
if (typeof input === "string") {
|
|
122
|
+
try {
|
|
123
|
+
parsed = JSON.parse(input);
|
|
124
|
+
} catch {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`LoomLensTool requires JSON input. Received: ${input.slice(0, 100)}`
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
parsed = input;
|
|
131
|
+
}
|
|
132
|
+
if (!parsed.job_description || !parsed.target_models?.length) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
"LoomLensTool requires job_description and target_models. Example: { job_description: 'Research agent', target_models: ['openai/gpt-4o'] }"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
return self.estimateSummary(parsed);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
function createLoomLensTool(config) {
|
|
143
|
+
return new LoomLensTool(config);
|
|
144
|
+
}
|
|
145
|
+
var SIGNALLOOM_PACKAGE_INFO = {
|
|
146
|
+
name: "signalloomai",
|
|
147
|
+
version: "1.0.0",
|
|
148
|
+
homepage: "https://signalloomai.com",
|
|
149
|
+
docs: "https://signalloomai.com/docs",
|
|
150
|
+
promptIntegrity: "https://signalloomai.com/prompt-integrity.html"
|
|
151
|
+
/** Prompt: This tool does NOT log prompts or job descriptions. */
|
|
152
|
+
};
|
|
153
|
+
export {
|
|
154
|
+
LoomLensTool,
|
|
155
|
+
SIGNALLOOM_PACKAGE_INFO,
|
|
156
|
+
createLoomLensTool
|
|
157
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "signalloomai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Signal Loom AI — LangChain tool wrapper for LoomLens AI token cost estimation",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://signalloomai.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/signalloom/signalloomai"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"langchain",
|
|
13
|
+
"llm",
|
|
14
|
+
"token",
|
|
15
|
+
"cost",
|
|
16
|
+
"estimation",
|
|
17
|
+
"ai-agent",
|
|
18
|
+
"ai-tools",
|
|
19
|
+
"gpt-4o",
|
|
20
|
+
"claude",
|
|
21
|
+
"gemini",
|
|
22
|
+
"openai",
|
|
23
|
+
"anthropic",
|
|
24
|
+
"ai-pipeline"
|
|
25
|
+
],
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "./dist/index.cjs",
|
|
28
|
+
"module": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js",
|
|
34
|
+
"require": "./dist/index.cjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
},
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"langchain": ">=0.1.0"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^20.0.0",
|
|
49
|
+
"tsup": "^8.0.0",
|
|
50
|
+
"typescript": "^5.0.0"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@langchain/core": ">=0.1.0"
|
|
54
|
+
}
|
|
55
|
+
}
|