@threaded/ai 1.0.26 → 1.0.27
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/.lore +65 -0
- package/dist/index.cjs +54 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +54 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/.lore
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
-- core pattern --
|
|
2
|
+
|
|
3
|
+
everything is built on compose/scope/model. compose chains steps, scope isolates context, model calls an LLM.
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
const workflow = compose(
|
|
7
|
+
scope({ system: "...", tools: [...] }, model({ model: "openai/gpt-4o" }))
|
|
8
|
+
)
|
|
9
|
+
const ctx = await workflow("user message")
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
-- key setup --
|
|
13
|
+
|
|
14
|
+
must call setKeys() before any model() call, or set env vars (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, XAI_API_KEY)
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
import { setKeys } from "@threaded/ai"
|
|
18
|
+
setKeys({ openai: process.env.OPENAI_API_KEY })
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
-- model naming --
|
|
22
|
+
|
|
23
|
+
always "provider/model-name": openai/gpt-4o, anthropic/claude-sonnet-4-5-20250929, google/gemini-2.5-flash, xai/grok-4-1-fast-non-reasoning. no prefix defaults to huggingface.
|
|
24
|
+
|
|
25
|
+
-- structured output --
|
|
26
|
+
|
|
27
|
+
pass schema (zod or json schema) to model(). response comes back as JSON in lastResponse.content. claude wraps it in markdown code fences - strip them before JSON.parse.
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
function extractResult(ctx) {
|
|
31
|
+
const last = ctx.history?.findLast(m => m.role === 'assistant')
|
|
32
|
+
if (!last?.content) return null
|
|
33
|
+
let text = typeof last.content === 'string' ? last.content : last.content[0]?.text || ''
|
|
34
|
+
const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/)
|
|
35
|
+
if (fenced) text = fenced[1]
|
|
36
|
+
return JSON.parse(text.trim())
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
-- pitfalls --
|
|
41
|
+
|
|
42
|
+
do NOT use Inherit.Nothing - it drops the user prompt entirely. use Inherit.Conversation (default) instead.
|
|
43
|
+
|
|
44
|
+
until: noToolsCalled() loops can cause runaway API calls (5-6+ per invocation). use maxCalls() on tools to limit.
|
|
45
|
+
|
|
46
|
+
silent scopes run analysis without polluting chat history but still accumulate token usage on ctx.usage.
|
|
47
|
+
|
|
48
|
+
events are local only in the scope where stream callback is set. nested silent scopes with their own stream get their own events.
|
|
49
|
+
|
|
50
|
+
-- rate limiting --
|
|
51
|
+
|
|
52
|
+
anthropic tier 1 has very low limits (30K input tokens/min). when using anthropic, add delays between calls and use maxCalls() aggressively. 90s backoff on rate limit errors.
|
|
53
|
+
|
|
54
|
+
-- token usage --
|
|
55
|
+
|
|
56
|
+
ctx.usage accumulates across all model() calls, tool loops, and nested scopes. always available after workflow completes:
|
|
57
|
+
{ promptTokens, completionTokens, totalTokens }
|
|
58
|
+
|
|
59
|
+
-- integration patterns --
|
|
60
|
+
|
|
61
|
+
SSE streaming: pass stream callback in scope config, write events to res as `data: ${JSON.stringify(event)}\n\n`
|
|
62
|
+
|
|
63
|
+
tool approval: use toolConfig.requireApproval + approvalCallback for gating dangerous tool execution in web UIs
|
|
64
|
+
|
|
65
|
+
MCP tools: createMCPTools(client) converts MCP server tools to native format. tools are prefixed with server name.
|
package/dist/index.cjs
CHANGED
|
@@ -1111,10 +1111,61 @@ var handleGoogleStream = async (response, ctx) => {
|
|
|
1111
1111
|
};
|
|
1112
1112
|
|
|
1113
1113
|
// src/providers/huggingface.ts
|
|
1114
|
+
var modelCache2 = /* @__PURE__ */ new Map();
|
|
1115
|
+
var formatMessages = (instructions, history) => {
|
|
1116
|
+
const messages = [];
|
|
1117
|
+
if (instructions) {
|
|
1118
|
+
messages.push({ role: "system", content: instructions });
|
|
1119
|
+
}
|
|
1120
|
+
for (const msg of history) {
|
|
1121
|
+
messages.push({ role: msg.role, content: msg.content });
|
|
1122
|
+
}
|
|
1123
|
+
return messages;
|
|
1124
|
+
};
|
|
1114
1125
|
var callHuggingFace = async (config, ctx) => {
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
)
|
|
1126
|
+
const { model: model2, instructions, schema } = config;
|
|
1127
|
+
const { pipeline } = await import("@huggingface/transformers");
|
|
1128
|
+
if (!modelCache2.has(model2)) {
|
|
1129
|
+
const generator2 = await pipeline("text-generation", model2, {
|
|
1130
|
+
dtype: "q4f16"
|
|
1131
|
+
});
|
|
1132
|
+
modelCache2.set(model2, generator2);
|
|
1133
|
+
}
|
|
1134
|
+
const generator = modelCache2.get(model2);
|
|
1135
|
+
const messages = formatMessages(instructions, ctx.history);
|
|
1136
|
+
if (schema) {
|
|
1137
|
+
const schemaMsg = messages.find((m) => m.role === "system");
|
|
1138
|
+
const schemaInstructions = [
|
|
1139
|
+
"you must respond with valid JSON matching this schema:",
|
|
1140
|
+
JSON.stringify(schema.schema, null, 2),
|
|
1141
|
+
"respond ONLY with the JSON object, no other text."
|
|
1142
|
+
].join("\n");
|
|
1143
|
+
if (schemaMsg) {
|
|
1144
|
+
schemaMsg.content += "\n\n" + schemaInstructions;
|
|
1145
|
+
} else {
|
|
1146
|
+
messages.unshift({ role: "system", content: schemaInstructions });
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
const output = await generator(messages, {
|
|
1150
|
+
max_new_tokens: 2048,
|
|
1151
|
+
do_sample: false
|
|
1152
|
+
});
|
|
1153
|
+
const generatedMessages = output[0].generated_text;
|
|
1154
|
+
const lastMessage = generatedMessages.at(-1);
|
|
1155
|
+
const content = lastMessage?.content || "";
|
|
1156
|
+
const msg = {
|
|
1157
|
+
role: "assistant",
|
|
1158
|
+
content
|
|
1159
|
+
};
|
|
1160
|
+
if (ctx.stream) {
|
|
1161
|
+
ctx.stream({ type: "content", content });
|
|
1162
|
+
}
|
|
1163
|
+
return {
|
|
1164
|
+
...ctx,
|
|
1165
|
+
lastResponse: msg,
|
|
1166
|
+
history: [...ctx.history, msg],
|
|
1167
|
+
usage: addUsage(ctx.usage, 0, 0, 0)
|
|
1168
|
+
};
|
|
1118
1169
|
};
|
|
1119
1170
|
|
|
1120
1171
|
// src/providers/xai.ts
|