@intentface/latch-core 0.9.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/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/agent.d.ts +200 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +9 -0
- package/dist/agent.js.map +1 -0
- package/dist/compaction.d.ts +33 -0
- package/dist/compaction.d.ts.map +1 -0
- package/dist/compaction.js +104 -0
- package/dist/compaction.js.map +1 -0
- package/dist/connections.d.ts +16 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +41 -0
- package/dist/connections.js.map +1 -0
- package/dist/context.d.ts +41 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +25 -0
- package/dist/context.js.map +1 -0
- package/dist/current-date.d.ts +12 -0
- package/dist/current-date.d.ts.map +1 -0
- package/dist/current-date.js +25 -0
- package/dist/current-date.js.map +1 -0
- package/dist/extensions.d.ts +333 -0
- package/dist/extensions.d.ts.map +1 -0
- package/dist/extensions.js +569 -0
- package/dist/extensions.js.map +1 -0
- package/dist/harness/index.d.ts +17 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +15 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/harness/tools.d.ts +88 -0
- package/dist/harness/tools.d.ts.map +1 -0
- package/dist/harness/tools.js +296 -0
- package/dist/harness/tools.js.map +1 -0
- package/dist/harness/web-fetch.d.ts +47 -0
- package/dist/harness/web-fetch.d.ts.map +1 -0
- package/dist/harness/web-fetch.js +247 -0
- package/dist/harness/web-fetch.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/limits.d.ts +152 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +97 -0
- package/dist/limits.js.map +1 -0
- package/dist/memory.d.ts +93 -0
- package/dist/memory.d.ts.map +1 -0
- package/dist/memory.js +13 -0
- package/dist/memory.js.map +1 -0
- package/dist/message.d.ts +46 -0
- package/dist/message.d.ts.map +1 -0
- package/dist/message.js +2 -0
- package/dist/message.js.map +1 -0
- package/dist/models/catalog.d.ts +56 -0
- package/dist/models/catalog.d.ts.map +1 -0
- package/dist/models/catalog.js +211 -0
- package/dist/models/catalog.js.map +1 -0
- package/dist/models/defaults.d.ts +23 -0
- package/dist/models/defaults.d.ts.map +1 -0
- package/dist/models/defaults.js +19 -0
- package/dist/models/defaults.js.map +1 -0
- package/dist/models/index.d.ts +23 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +19 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/prompt-caching.d.ts +19 -0
- package/dist/models/prompt-caching.d.ts.map +1 -0
- package/dist/models/prompt-caching.js +18 -0
- package/dist/models/prompt-caching.js.map +1 -0
- package/dist/models/provider.d.ts +19 -0
- package/dist/models/provider.d.ts.map +1 -0
- package/dist/models/provider.js +22 -0
- package/dist/models/provider.js.map +1 -0
- package/dist/models/reasoning.d.ts +21 -0
- package/dist/models/reasoning.d.ts.map +1 -0
- package/dist/models/reasoning.js +59 -0
- package/dist/models/reasoning.js.map +1 -0
- package/dist/pricing.d.ts +52 -0
- package/dist/pricing.d.ts.map +1 -0
- package/dist/pricing.js +37 -0
- package/dist/pricing.js.map +1 -0
- package/dist/principal.d.ts +37 -0
- package/dist/principal.d.ts.map +1 -0
- package/dist/principal.js +30 -0
- package/dist/principal.js.map +1 -0
- package/dist/projections.d.ts +37 -0
- package/dist/projections.d.ts.map +1 -0
- package/dist/projections.js +128 -0
- package/dist/projections.js.map +1 -0
- package/dist/prompt-caching.d.ts +106 -0
- package/dist/prompt-caching.d.ts.map +1 -0
- package/dist/prompt-caching.js +165 -0
- package/dist/prompt-caching.js.map +1 -0
- package/dist/runtime.d.ts +670 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +2425 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scheduler.d.ts +31 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +43 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/storage.d.ts +389 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +38 -0
- package/dist/storage.js.map +1 -0
- package/dist/telemetry.d.ts +155 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +2 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/vault-node.d.ts +20 -0
- package/dist/vault-node.d.ts.map +1 -0
- package/dist/vault-node.js +30 -0
- package/dist/vault-node.js.map +1 -0
- package/dist/vault.d.ts +62 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +88 -0
- package/dist/vault.js.map +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt-caching plans: which provider options a turn should set so the model
|
|
3
|
+
* provider caches the stable prompt prefix (tool definitions, system prompt,
|
|
4
|
+
* conversation history) instead of re-billing it every step.
|
|
5
|
+
*
|
|
6
|
+
* Kept provider-generic in core: the PLATFORM decides which provider a model id
|
|
7
|
+
* belongs to (it owns the catalog) and calls `promptCachingPlanFor` from its
|
|
8
|
+
* `RuntimeConfig.resolvePromptCaching` hook; core only applies the plan in
|
|
9
|
+
* `buildTurn`. Providers not named here (e.g. Google: implicit caching only)
|
|
10
|
+
* get no plan and are untouched.
|
|
11
|
+
*
|
|
12
|
+
* Anthropic layout — three of the four allowed `cache_control` breakpoints:
|
|
13
|
+
* 1. The LAST function tool definition. Tools render before the system prompt
|
|
14
|
+
* in the request, so this keeps the (often large, MCP-heavy) tool prefix
|
|
15
|
+
* cached even when the system block changes mid-conversation (e.g. a
|
|
16
|
+
* memory-index write).
|
|
17
|
+
* 2. The system message that holds the agent instructions + memory block. The
|
|
18
|
+
* day-granular date line is a SEPARATE, unmarked system message after it,
|
|
19
|
+
* so the daily date flip never invalidates this breakpoint.
|
|
20
|
+
* 3. A request-level (top-level) `cache_control` — Anthropic's automatic
|
|
21
|
+
* caching: the API places a breakpoint on the last cacheable block of the
|
|
22
|
+
* request. The AI SDK re-sends call-level providerOptions on every step of
|
|
23
|
+
* the tool loop, so this breakpoint ROLLS to the newest tool result with no
|
|
24
|
+
* per-step code. Note: top-level cache_control is a first-party Claude API
|
|
25
|
+
* feature (not Bedrock/Vertex); block-level markers work everywhere. Also
|
|
26
|
+
* note the SDK's client-side breakpoint validator counts only block-level
|
|
27
|
+
* markers, so the request-level one is invisible to it — harmless.
|
|
28
|
+
*
|
|
29
|
+
* TTL is left at the provider default (5m). Agents whose turns arrive slower
|
|
30
|
+
* than that won't benefit — that's surfaced by the platform's caching lint,
|
|
31
|
+
* not worked around here.
|
|
32
|
+
*/
|
|
33
|
+
/** A cache-control marker in the shape the Anthropic provider expects. */
|
|
34
|
+
const EPHEMERAL = { type: "ephemeral" };
|
|
35
|
+
/**
|
|
36
|
+
* The caching plan for a provider family (`"anthropic"`, `"openai"`, …).
|
|
37
|
+
* `cacheKeySuffix` scopes OpenAI's cache routing key beyond the agent name —
|
|
38
|
+
* pass a per-principal key for agents whose system prompt is per-principal
|
|
39
|
+
* (e.g. memory-enabled agents), so structurally different prefixes don't
|
|
40
|
+
* co-route to one shard.
|
|
41
|
+
*/
|
|
42
|
+
export function promptCachingPlanFor(provider, opts) {
|
|
43
|
+
if (provider === "anthropic") {
|
|
44
|
+
return {
|
|
45
|
+
requestProviderOptions: { anthropic: { cacheControl: { ...EPHEMERAL } } },
|
|
46
|
+
systemProviderOptions: { anthropic: { cacheControl: { ...EPHEMERAL } } },
|
|
47
|
+
toolProviderOptions: { anthropic: { cacheControl: { ...EPHEMERAL } } },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (provider === "openai") {
|
|
51
|
+
const key = opts.cacheKeySuffix
|
|
52
|
+
? `latch:agent:${opts.agent}:${opts.cacheKeySuffix}`
|
|
53
|
+
: `latch:agent:${opts.agent}`;
|
|
54
|
+
// OpenAI caps prompt_cache_key at 64 chars and 400s the whole turn past
|
|
55
|
+
// it — agent names and principal keys are unbounded, so an over-long key
|
|
56
|
+
// collapses to a deterministic hash of the full key material (routing
|
|
57
|
+
// only needs stability, not readability).
|
|
58
|
+
const bounded = key.length <= 64 ? key : `latch:${fnv1a64(key)}`;
|
|
59
|
+
return { requestProviderOptions: { openai: { promptCacheKey: bounded } } };
|
|
60
|
+
}
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The DEFAULT caching plan, used when the runtime has no `resolvePromptCaching`
|
|
65
|
+
* hook: derive the provider family from the model object itself — every AI SDK
|
|
66
|
+
* `LanguageModel` carries a `provider` string (`"anthropic.messages"`,
|
|
67
|
+
* `"openai.responses"`, …) — and apply {@link promptCachingPlanFor}. Measured
|
|
68
|
+
* on a real MCP-heavy agent, this is a ~6x difference in unit cost (a ~32k-token
|
|
69
|
+
* tool catalogue re-billed every step vs read from cache), which is not a
|
|
70
|
+
* default a customer should have to discover by reading source.
|
|
71
|
+
*
|
|
72
|
+
* Deliberately conservative: only FIRST-PARTY Anthropic/OpenAI provider ids
|
|
73
|
+
* match (Bedrock/Vertex ids don't contain these substrings), because the
|
|
74
|
+
* Anthropic plan's request-level `cache_control` is a first-party feature.
|
|
75
|
+
* Unknown providers get no plan and are untouched. Opt out entirely with
|
|
76
|
+
* `resolvePromptCaching: () => undefined`, or per turn with
|
|
77
|
+
* `promptCaching: false`.
|
|
78
|
+
*/
|
|
79
|
+
export function defaultPromptCachingPlan(model, agent) {
|
|
80
|
+
const provider = typeof model === "object" && model !== null
|
|
81
|
+
? String(model.provider ?? "")
|
|
82
|
+
: "";
|
|
83
|
+
const family = provider.includes("anthropic")
|
|
84
|
+
? "anthropic"
|
|
85
|
+
: provider.includes("openai")
|
|
86
|
+
? "openai"
|
|
87
|
+
: undefined;
|
|
88
|
+
return promptCachingPlanFor(family, { agent });
|
|
89
|
+
}
|
|
90
|
+
/** FNV-1a 64-bit over a string — dependency-free stable fingerprint. */
|
|
91
|
+
function fnv1a64(input) {
|
|
92
|
+
let hash = 0xcbf29ce484222325n;
|
|
93
|
+
const prime = 0x100000001b3n;
|
|
94
|
+
for (let i = 0; i < input.length; i++) {
|
|
95
|
+
hash ^= BigInt(input.charCodeAt(i));
|
|
96
|
+
hash = (hash * prime) & 0xffffffffffffffffn;
|
|
97
|
+
}
|
|
98
|
+
return hash.toString(16).padStart(16, "0");
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* One-level-deep merge of providerOptions objects (per provider key), so e.g.
|
|
102
|
+
* `{ anthropic: { thinking } }` from reasoning and `{ anthropic: { cacheControl } }`
|
|
103
|
+
* from caching coexist — a plain spread would clobber one with the other. Later
|
|
104
|
+
* sources win on conflicting inner keys. Returns undefined when nothing to merge.
|
|
105
|
+
*/
|
|
106
|
+
export function mergeProviderOptions(...sources) {
|
|
107
|
+
const present = sources.filter((s) => !!s);
|
|
108
|
+
if (present.length === 0)
|
|
109
|
+
return undefined;
|
|
110
|
+
if (present.length === 1)
|
|
111
|
+
return present[0];
|
|
112
|
+
const out = {};
|
|
113
|
+
for (const source of present) {
|
|
114
|
+
for (const [provider, options] of Object.entries(source)) {
|
|
115
|
+
const prev = out[provider];
|
|
116
|
+
out[provider] =
|
|
117
|
+
prev && typeof prev === "object" && options && typeof options === "object"
|
|
118
|
+
? { ...prev, ...options }
|
|
119
|
+
: options;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Stable fingerprint of a toolset (FNV-1a 64-bit over the sorted names) —
|
|
126
|
+
* equality is all that matters (same hash ⇔ same tool names), so a
|
|
127
|
+
* dependency-free non-cryptographic hash beats pulling in node:crypto (core
|
|
128
|
+
* stays runtime-agnostic). Stored on the run row to detect toolset churn
|
|
129
|
+
* across a chat's turns, one of the main prompt-cache invalidators.
|
|
130
|
+
*/
|
|
131
|
+
export function toolsetHash(names) {
|
|
132
|
+
return fnv1a64([...names].sort().join(","));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Mark the LAST active function tool with the given providerOptions (in place).
|
|
136
|
+
* Skips provider-executed tools (`type: "provider"`, e.g. Anthropic's native
|
|
137
|
+
* web_search/web_fetch) — the provider silently drops `cache_control` on those —
|
|
138
|
+
* and, when `activeNames` is given, tools the turn filtered out via
|
|
139
|
+
* `activeTools` (a marker on an unsent tool would vanish). Returns the marked
|
|
140
|
+
* tool name, or undefined when no eligible tool exists.
|
|
141
|
+
*/
|
|
142
|
+
export function markLastFunctionTool(tools, providerOptions, activeNames) {
|
|
143
|
+
const active = activeNames ? new Set(activeNames) : undefined;
|
|
144
|
+
const names = Object.keys(tools);
|
|
145
|
+
for (let i = names.length - 1; i >= 0; i--) {
|
|
146
|
+
const name = names[i];
|
|
147
|
+
if (active && !active.has(name))
|
|
148
|
+
continue;
|
|
149
|
+
const t = tools[name];
|
|
150
|
+
if (!t || typeof t !== "object")
|
|
151
|
+
continue;
|
|
152
|
+
// "provider" (and any future provider-executed variant) can't carry
|
|
153
|
+
// cache_control; everything else (function/dynamic) serializes as a
|
|
154
|
+
// client tool definition and can.
|
|
155
|
+
if (typeof t.type === "string" && t.type.startsWith("provider"))
|
|
156
|
+
continue;
|
|
157
|
+
tools[name] = {
|
|
158
|
+
...t,
|
|
159
|
+
providerOptions: mergeProviderOptions(t.providerOptions, providerOptions),
|
|
160
|
+
};
|
|
161
|
+
return name;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=prompt-caching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-caching.js","sourceRoot":"","sources":["../src/prompt-caching.ts"],"names":[],"mappings":"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"}
|