@cloc/provider-ai-sdk 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/LICENSE +21 -0
- package/dist/agent.d.ts +93 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +359 -0
- package/dist/agent.js.map +1 -0
- package/dist/config.d.ts +85 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +101 -0
- package/dist/config.js.map +1 -0
- package/dist/gateway.d.ts +74 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +96 -0
- package/dist/gateway.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/memory-tool.d.ts +63 -0
- package/dist/memory-tool.d.ts.map +1 -0
- package/dist/memory-tool.js +183 -0
- package/dist/memory-tool.js.map +1 -0
- package/dist/output.d.ts +49 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +41 -0
- package/dist/output.js.map +1 -0
- package/dist/plugin.d.ts +74 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +86 -0
- package/dist/plugin.js.map +1 -0
- package/dist/request.d.ts +82 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/request.js +80 -0
- package/dist/request.js.map +1 -0
- package/dist/safety.d.ts +54 -0
- package/dist/safety.d.ts.map +1 -0
- package/dist/safety.js +0 -0
- package/dist/safety.js.map +1 -0
- package/dist/secrets.d.ts +51 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +47 -0
- package/dist/secrets.js.map +1 -0
- package/dist/skills-loader.d.ts +76 -0
- package/dist/skills-loader.d.ts.map +1 -0
- package/dist/skills-loader.js +99 -0
- package/dist/skills-loader.js.map +1 -0
- package/dist/stream.d.ts +58 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +59 -0
- package/dist/stream.js.map +1 -0
- package/dist/tokens.d.ts +17 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +17 -0
- package/dist/tokens.js.map +1 -0
- package/dist/tool-loop.d.ts +98 -0
- package/dist/tool-loop.d.ts.map +1 -0
- package/dist/tool-loop.js +210 -0
- package/dist/tool-loop.js.map +1 -0
- package/dist/trace.d.ts +78 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +39 -0
- package/dist/trace.js.map +1 -0
- package/dist/validate.d.ts +54 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +81 -0
- package/dist/validate.js.map +1 -0
- package/package.json +55 -0
- package/src/agent.ts +487 -0
- package/src/config.ts +147 -0
- package/src/gateway.ts +126 -0
- package/src/index.ts +101 -0
- package/src/memory-tool.ts +219 -0
- package/src/output.ts +67 -0
- package/src/plugin.ts +123 -0
- package/src/request.ts +178 -0
- package/src/safety.ts +0 -0
- package/src/secrets.ts +71 -0
- package/src/skills-loader.ts +153 -0
- package/src/stream.ts +80 -0
- package/src/tokens.ts +82 -0
- package/src/tool-loop.ts +268 -0
- package/src/trace.ts +87 -0
- package/src/validate.ts +118 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk · config.ts — the declarative `cloc.yml` `agent:` slice (data-model §5).
|
|
3
|
+
*
|
|
4
|
+
* Selection + tuning is data, never code (Constitution Principle 1; Appendix L.1 — `cloc.yml`
|
|
5
|
+
* is declarative/non-executable, never `cloc.config.ts`). The model is a FIELD (a gateway
|
|
6
|
+
* `provider/model` string), changeable with NO adapter-code edit (FR-007, FR-014). The gateway
|
|
7
|
+
* credential is referenced BY NAME (`secretRef`) — a secret VALUE in `cloc.yml` is rejected
|
|
8
|
+
* (FR-009, NFR-005, Principle 9).
|
|
9
|
+
*
|
|
10
|
+
* TODO(C2 — spec Clarification 2): the bounded-repair `maxAttempts` default below is provisional;
|
|
11
|
+
* the design doc names "validate / repair" without a limit. Routed to Governance (research.md C2).
|
|
12
|
+
* TODO(C1 — spec Clarification 1): whether a built-in default provider/model ships (so the block
|
|
13
|
+
* is optional) vs. BYO before the first synthesis request. Routed to Governance (research.md C1).
|
|
14
|
+
*/
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
/** Provisional default repair bound. TODO(C2): routed to Governance (research.md C2). */
|
|
17
|
+
export const DEFAULT_REPAIR_POLICY = {
|
|
18
|
+
maxAttempts: 2,
|
|
19
|
+
onExhaustion: "reject",
|
|
20
|
+
};
|
|
21
|
+
/** This plugin's id; also the default `provider` value when the block omits it. */
|
|
22
|
+
export const PROVIDER_ID = "provider-ai-sdk";
|
|
23
|
+
const ModelFieldSchema = z.object({
|
|
24
|
+
vendor: z.string().min(1),
|
|
25
|
+
name: z.string().min(1),
|
|
26
|
+
});
|
|
27
|
+
const RoutingSchema = z.object({
|
|
28
|
+
fallbacks: z.array(ModelFieldSchema).default([]),
|
|
29
|
+
});
|
|
30
|
+
const RepairSchema = z.object({
|
|
31
|
+
maxAttempts: z.number().int().positive(),
|
|
32
|
+
onExhaustion: z.literal("reject"),
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* A `secretRef` is a NAME, never a value. We reject anything that looks like an inlined
|
|
36
|
+
* credential (whitespace, an obvious key prefix, or an over-long opaque token) so a secret
|
|
37
|
+
* value in `cloc.yml` fails loud (FR-009, NFR-005, Principle 9). Heuristic, but conservative:
|
|
38
|
+
* real env-style names are short, contain no spaces, and are not `sk-…`/`gsk_…`-style keys.
|
|
39
|
+
*/
|
|
40
|
+
function looksLikeSecretValue(ref) {
|
|
41
|
+
if (/\s/.test(ref))
|
|
42
|
+
return true; // names have no whitespace
|
|
43
|
+
if (/^(sk|gsk|pk|rk|api|key|bearer)[-_]/i.test(ref))
|
|
44
|
+
return true; // common key prefixes
|
|
45
|
+
if (ref.length > 64)
|
|
46
|
+
return true; // names are short; opaque tokens are long
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const SecretRefSchema = z
|
|
50
|
+
.string()
|
|
51
|
+
.min(1)
|
|
52
|
+
.refine((v) => !looksLikeSecretValue(v), {
|
|
53
|
+
message: "secretRef must be a NAME, never an inlined secret value — store the value in the secrets provider (FR-009, NFR-005, Principle 9)",
|
|
54
|
+
});
|
|
55
|
+
/** The raw `agent:` block schema as it appears in `cloc.yml`. */
|
|
56
|
+
export const AgentConfigSchema = z.object({
|
|
57
|
+
provider: z.string().min(1).default(PROVIDER_ID),
|
|
58
|
+
model: ModelFieldSchema,
|
|
59
|
+
routing: RoutingSchema.optional(),
|
|
60
|
+
secretRef: SecretRefSchema,
|
|
61
|
+
repair: RepairSchema.optional(),
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Parse + validate a raw `cloc.yml` `agent:` block into a normalized {@link AgentConfig}.
|
|
65
|
+
* Throws (Zod) on an invalid block — including a `secretRef` that holds a value, not a name.
|
|
66
|
+
*/
|
|
67
|
+
export function parseAgentConfig(raw) {
|
|
68
|
+
const parsed = AgentConfigSchema.parse(raw);
|
|
69
|
+
return {
|
|
70
|
+
provider: parsed.provider,
|
|
71
|
+
model: parsed.model,
|
|
72
|
+
...(parsed.routing ? { routing: { fallbacks: parsed.routing.fallbacks } } : {}),
|
|
73
|
+
secretRef: parsed.secretRef,
|
|
74
|
+
repair: parsed.repair ?? DEFAULT_REPAIR_POLICY,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Render one {@link ModelField} as the gateway `provider/model` string the SDK routes on. */
|
|
78
|
+
export function modelFieldToString(field) {
|
|
79
|
+
return `${field.vendor}/${field.name}`;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The ordered list of `provider/model` strings to try: primary first, then failovers, with
|
|
83
|
+
* consecutive/duplicate entries collapsed so the same provider is never retried twice in a row
|
|
84
|
+
* (a fallback identical to the primary would only waste a hop). Order is otherwise preserved.
|
|
85
|
+
*/
|
|
86
|
+
export function modelChain(config) {
|
|
87
|
+
const primary = modelFieldToString(config.model);
|
|
88
|
+
const fallbacks = (config.routing?.fallbacks ?? []).map(modelFieldToString);
|
|
89
|
+
const ordered = [primary, ...fallbacks];
|
|
90
|
+
// Dedupe while preserving first-seen order (a duplicate fallback adds no failover value).
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
const chain = [];
|
|
93
|
+
for (const id of ordered) {
|
|
94
|
+
if (seen.has(id))
|
|
95
|
+
continue;
|
|
96
|
+
seen.add(id);
|
|
97
|
+
chain.push(id);
|
|
98
|
+
}
|
|
99
|
+
return chain;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk · gateway.ts — hosted-first routing via the Vercel AI Gateway (FR-006/7/8).
|
|
3
|
+
*
|
|
4
|
+
* A declarative `provider/model` string ("anthropic/claude-…", "openai/gpt-…") becomes a routed,
|
|
5
|
+
* failover-capable inference call. The adapter assumes NO local GPU/runtime (FR-006, invariant 3):
|
|
6
|
+
* every call goes through the gateway. Per-request failover walks `routing.fallbacks` in order;
|
|
7
|
+
* on full exhaustion it raises a fatal `gateway-exhausted` error — never partial/fabricated output
|
|
8
|
+
* (edge case, data-model §4).
|
|
9
|
+
*
|
|
10
|
+
* AI SDK v6 surface (verified against the v6 docs, not stale memory):
|
|
11
|
+
* - The AI Gateway is the DEFAULT global provider, so a plain `provider/model` string passed as
|
|
12
|
+
* `model:` to `generateText`/`streamText` is already a routed gateway call.
|
|
13
|
+
* - The gateway credential is the `AI_GATEWAY_API_KEY` env var; we resolve it BY NAME via the
|
|
14
|
+
* secrets boundary (secrets.ts) and hand it to the SDK through the gateway provider options.
|
|
15
|
+
* - `gateway` (from 'ai') lets us bind the resolved key explicitly rather than relying on ambient
|
|
16
|
+
* env, keeping the credential under the least-privilege grant (secrets.ts).
|
|
17
|
+
*/
|
|
18
|
+
import type { LanguageModel } from "ai";
|
|
19
|
+
import { type AgentConfig } from "./config.js";
|
|
20
|
+
/**
|
|
21
|
+
* The well-known surfaced error codes. A FREE-FORM `string` is still accepted (the param type is
|
|
22
|
+
* `AgentErrorCode | (string & {})`) so adapters/hosts can mint their own codes — but the named set
|
|
23
|
+
* gives callers autocomplete + exhaustiveness without narrowing the existing `string` contract.
|
|
24
|
+
*/
|
|
25
|
+
export type AgentErrorCode = "validation-exhausted" | "gateway-exhausted" | "tool-failed" | "aborted";
|
|
26
|
+
/** A fatal, surfaced agent error (mirrors the contract's AgentError, adapter-internal). */
|
|
27
|
+
export declare class AgentError extends Error {
|
|
28
|
+
/** One of {@link AgentErrorCode} (or a host-minted string). */
|
|
29
|
+
readonly code: AgentErrorCode | (string & {});
|
|
30
|
+
/** True only when NO valid output was produced; any streamed partial MUST be invalidated. */
|
|
31
|
+
readonly fatal: boolean;
|
|
32
|
+
constructor(
|
|
33
|
+
/** One of {@link AgentErrorCode} (or a host-minted string). */
|
|
34
|
+
code: AgentErrorCode | (string & {}), message: string,
|
|
35
|
+
/** True only when NO valid output was produced; any streamed partial MUST be invalidated. */
|
|
36
|
+
fatal?: boolean, options?: {
|
|
37
|
+
cause?: unknown;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** True when `err` is an abort (an `AbortError`/`DOMException` name, or our `aborted` code). */
|
|
41
|
+
export declare function isAbortError(err: unknown): boolean;
|
|
42
|
+
/** A resolved gateway provider bound to the credential (or the ambient default). */
|
|
43
|
+
export interface ResolvedGateway {
|
|
44
|
+
/** Turn a `provider/model` string into a routed language model the AI SDK can call. */
|
|
45
|
+
model(id: string): LanguageModel;
|
|
46
|
+
/** The ordered `provider/model` chain to try: primary, then failovers. */
|
|
47
|
+
chain: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build a gateway bound to the resolved credential. When `apiKey` is provided we create a scoped
|
|
51
|
+
* gateway so the key stays under the plugin's grant; otherwise we fall back to the ambient default
|
|
52
|
+
* provider (the SDK reads `AI_GATEWAY_API_KEY` itself), used in tests / OIDC deployments.
|
|
53
|
+
*/
|
|
54
|
+
export declare function resolveGateway(config: AgentConfig, apiKey?: string): ResolvedGateway;
|
|
55
|
+
/**
|
|
56
|
+
* Run `attempt` against each model in the failover chain in order. The first success wins;
|
|
57
|
+
* `onAttempt` reports the routed id + hop index so the trace can record `gateway.fallback`.
|
|
58
|
+
* If every provider errors, raise a fatal `gateway-exhausted` error (FR-008, edge case).
|
|
59
|
+
*
|
|
60
|
+
* `attempt` receives the routed {@link LanguageModel} and the hop index (0 = primary).
|
|
61
|
+
*
|
|
62
|
+
* ABORT short-circuit: if an attempt throws because the caller's {@link AbortSignal} fired, the
|
|
63
|
+
* chain STOPS immediately and an `aborted` AgentError is raised — an explicit cancel must NOT burn
|
|
64
|
+
* every fallback hop (it is not a provider failure; §conformance C1 / A6). Pass `opts.signal` so the
|
|
65
|
+
* loop can also reject BEFORE the next hop if the signal fires between attempts.
|
|
66
|
+
*/
|
|
67
|
+
export declare function withFailover<T>(gw: ResolvedGateway, attempt: (model: LanguageModel, modelId: string, hop: number) => Promise<T>, onAttempt?: (modelId: string, hop: number) => void, opts?: {
|
|
68
|
+
signal?: AbortSignal;
|
|
69
|
+
}): Promise<{
|
|
70
|
+
value: T;
|
|
71
|
+
modelId: string;
|
|
72
|
+
hop: number;
|
|
73
|
+
}>;
|
|
74
|
+
//# sourceMappingURL=gateway.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxC,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,cAAc,GACtB,sBAAsB,GACtB,mBAAmB,GACnB,aAAa,GACb,SAAS,CAAC;AAEd,2FAA2F;AAC3F,qBAAa,UAAW,SAAQ,KAAK;IAEjC,+DAA+D;IAC/D,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC;IAE7C,6FAA6F;IAC7F,QAAQ,CAAC,KAAK,EAAE,OAAO;;IAJvB,+DAA+D;IACtD,IAAI,EAAE,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EAC7C,OAAO,EAAE,MAAM;IACf,6FAA6F;IACpF,KAAK,GAAE,OAAc,EAC9B,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAKhC;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAIlD;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAAC;IACjC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAMpF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,EAAE,EAAE,eAAe,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,EAC3E,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,EAClD,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,WAAW,CAAA;CAAE,GAC9B,OAAO,CAAC;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCrD"}
|
package/dist/gateway.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk · gateway.ts — hosted-first routing via the Vercel AI Gateway (FR-006/7/8).
|
|
3
|
+
*
|
|
4
|
+
* A declarative `provider/model` string ("anthropic/claude-…", "openai/gpt-…") becomes a routed,
|
|
5
|
+
* failover-capable inference call. The adapter assumes NO local GPU/runtime (FR-006, invariant 3):
|
|
6
|
+
* every call goes through the gateway. Per-request failover walks `routing.fallbacks` in order;
|
|
7
|
+
* on full exhaustion it raises a fatal `gateway-exhausted` error — never partial/fabricated output
|
|
8
|
+
* (edge case, data-model §4).
|
|
9
|
+
*
|
|
10
|
+
* AI SDK v6 surface (verified against the v6 docs, not stale memory):
|
|
11
|
+
* - The AI Gateway is the DEFAULT global provider, so a plain `provider/model` string passed as
|
|
12
|
+
* `model:` to `generateText`/`streamText` is already a routed gateway call.
|
|
13
|
+
* - The gateway credential is the `AI_GATEWAY_API_KEY` env var; we resolve it BY NAME via the
|
|
14
|
+
* secrets boundary (secrets.ts) and hand it to the SDK through the gateway provider options.
|
|
15
|
+
* - `gateway` (from 'ai') lets us bind the resolved key explicitly rather than relying on ambient
|
|
16
|
+
* env, keeping the credential under the least-privilege grant (secrets.ts).
|
|
17
|
+
*/
|
|
18
|
+
import { gateway as defaultGateway, createGateway } from "ai";
|
|
19
|
+
import { modelChain } from "./config.js";
|
|
20
|
+
/** A fatal, surfaced agent error (mirrors the contract's AgentError, adapter-internal). */
|
|
21
|
+
export class AgentError extends Error {
|
|
22
|
+
code;
|
|
23
|
+
fatal;
|
|
24
|
+
constructor(
|
|
25
|
+
/** One of {@link AgentErrorCode} (or a host-minted string). */
|
|
26
|
+
code, message,
|
|
27
|
+
/** True only when NO valid output was produced; any streamed partial MUST be invalidated. */
|
|
28
|
+
fatal = true, options) {
|
|
29
|
+
super(message, options);
|
|
30
|
+
this.code = code;
|
|
31
|
+
this.fatal = fatal;
|
|
32
|
+
this.name = "AgentError";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** True when `err` is an abort (an `AbortError`/`DOMException` name, or our `aborted` code). */
|
|
36
|
+
export function isAbortError(err) {
|
|
37
|
+
if (err instanceof AgentError)
|
|
38
|
+
return err.code === "aborted";
|
|
39
|
+
const name = err?.name;
|
|
40
|
+
return name === "AbortError" || name === "TimeoutError";
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build a gateway bound to the resolved credential. When `apiKey` is provided we create a scoped
|
|
44
|
+
* gateway so the key stays under the plugin's grant; otherwise we fall back to the ambient default
|
|
45
|
+
* provider (the SDK reads `AI_GATEWAY_API_KEY` itself), used in tests / OIDC deployments.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveGateway(config, apiKey) {
|
|
48
|
+
const provider = apiKey ? createGateway({ apiKey }) : defaultGateway;
|
|
49
|
+
return {
|
|
50
|
+
model: (id) => provider(id),
|
|
51
|
+
chain: modelChain(config),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Run `attempt` against each model in the failover chain in order. The first success wins;
|
|
56
|
+
* `onAttempt` reports the routed id + hop index so the trace can record `gateway.fallback`.
|
|
57
|
+
* If every provider errors, raise a fatal `gateway-exhausted` error (FR-008, edge case).
|
|
58
|
+
*
|
|
59
|
+
* `attempt` receives the routed {@link LanguageModel} and the hop index (0 = primary).
|
|
60
|
+
*
|
|
61
|
+
* ABORT short-circuit: if an attempt throws because the caller's {@link AbortSignal} fired, the
|
|
62
|
+
* chain STOPS immediately and an `aborted` AgentError is raised — an explicit cancel must NOT burn
|
|
63
|
+
* every fallback hop (it is not a provider failure; §conformance C1 / A6). Pass `opts.signal` so the
|
|
64
|
+
* loop can also reject BEFORE the next hop if the signal fires between attempts.
|
|
65
|
+
*/
|
|
66
|
+
export async function withFailover(gw, attempt, onAttempt, opts) {
|
|
67
|
+
// A chain MUST have at least one model; an empty chain is a config error, surfaced clearly.
|
|
68
|
+
if (gw.chain.length === 0) {
|
|
69
|
+
throw new AgentError("gateway-exhausted", "no gateway model configured (empty failover chain)", true);
|
|
70
|
+
}
|
|
71
|
+
let lastError;
|
|
72
|
+
for (let hop = 0; hop < gw.chain.length; hop++) {
|
|
73
|
+
const modelId = gw.chain[hop];
|
|
74
|
+
if (modelId === undefined)
|
|
75
|
+
continue;
|
|
76
|
+
// Cancelled between hops → reject with `aborted` rather than starting another provider.
|
|
77
|
+
if (opts?.signal?.aborted) {
|
|
78
|
+
throw new AgentError("aborted", "request aborted before completing", true, { cause: lastError });
|
|
79
|
+
}
|
|
80
|
+
onAttempt?.(modelId, hop);
|
|
81
|
+
try {
|
|
82
|
+
const value = await attempt(gw.model(modelId), modelId, hop);
|
|
83
|
+
return { value, modelId, hop };
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
lastError = err;
|
|
87
|
+
// An abort is a cancel, not a provider failure: stop the chain immediately (don't fail over).
|
|
88
|
+
if (isAbortError(err) || opts?.signal?.aborted) {
|
|
89
|
+
throw new AgentError("aborted", "request aborted during generation", true, { cause: err });
|
|
90
|
+
}
|
|
91
|
+
// otherwise try the next failover; the loop exhausting means all providers failed.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw new AgentError("gateway-exhausted", `all ${gw.chain.length} gateway provider(s) failed: [${gw.chain.join(", ")}]`, true, { cause: lastError });
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=gateway.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gateway.js","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk — the default AgentProvider, backed by the Vercel AI SDK v6
|
|
3
|
+
* (+ AI Gateway, hosted-first). It implements the vendor-free `AgentProvider` contract owned by
|
|
4
|
+
* @cloc/core (generate/stream), routes hosted-first through the AI Gateway, and ends in a
|
|
5
|
+
* validated structured Output (`Output.object` + Zod) that is the json-render UI plan / IR.
|
|
6
|
+
*
|
|
7
|
+
* This package is the ONLY place `ai` (the Vercel AI SDK) is imported — @cloc/core carries no
|
|
8
|
+
* vendor edge (§34, §43 Listing 15; FR-002, Constitution Principle 8). Future siblings under
|
|
9
|
+
* packages/plugins: provider-ai-langchain, provider-ai-claude, provider-ai-open-ai (§34).
|
|
10
|
+
*
|
|
11
|
+
* The default export is the `definePlugin(...)` value the kernel loads; the named exports expose
|
|
12
|
+
* the Agent + its typed surface for hosts and tests.
|
|
13
|
+
*/
|
|
14
|
+
import { plugin } from "./plugin.js";
|
|
15
|
+
export default plugin;
|
|
16
|
+
export { plugin, agentProvider, agentDepsFromContext, declaredNeeds, PLUGIN_NAME, GATEWAY_HOST } from "./plugin.js";
|
|
17
|
+
export type { AgentBootContext } from "./plugin.js";
|
|
18
|
+
export { AiSdkAgent, defaultRepairPrompt } from "./agent.js";
|
|
19
|
+
export type { AgentDeps } from "./agent.js";
|
|
20
|
+
export { parseAgentConfig, AgentConfigSchema, modelChain, modelFieldToString, DEFAULT_REPAIR_POLICY, PROVIDER_ID, } from "./config.js";
|
|
21
|
+
export type { AgentConfig, ModelField, GatewayRouting, RepairPolicy, RawAgentConfig } from "./config.js";
|
|
22
|
+
export { needsFor, resolveGatewayKey, assertNoInlineSecret } from "./secrets.js";
|
|
23
|
+
export type { SecretHandle, AgentNeeds } from "./secrets.js";
|
|
24
|
+
export { resolveGateway, withFailover, AgentError, isAbortError } from "./gateway.js";
|
|
25
|
+
export type { ResolvedGateway, AgentErrorCode } from "./gateway.js";
|
|
26
|
+
export { outputSpecFor, makeStructuredOutput } from "./output.js";
|
|
27
|
+
export type { StructuredOutput } from "./output.js";
|
|
28
|
+
export { validateOrRepair, validateOnce, ISSUE_SUMMARY_LIMIT } from "./validate.js";
|
|
29
|
+
export type { ValidateOutcome, ValidationIssue, ValidateEvents } from "./validate.js";
|
|
30
|
+
export { buildToolSet, buildAgenticToolSet, stopAfter, toAiStopWhen, toAiPrepareStep, DEFAULT_MAX_STEPS, } from "./tool-loop.js";
|
|
31
|
+
export type { LoopEvent, PrepareStepResultModel } from "./tool-loop.js";
|
|
32
|
+
export { unstorageMemoryStore, buildMemoryTools, MEMORY_ROOT, MEMORY_TOOL_NAMES, } from "./memory-tool.js";
|
|
33
|
+
export type { UnstorageLike } from "./memory-tool.js";
|
|
34
|
+
export { skillMetadata, frameSkillsForPrompt, activateSkill, openBundled, } from "./skills-loader.js";
|
|
35
|
+
export type { SkillMetadataLine, ActivateResult, SkillActivated, SkillGateDenied, OpenBundledResult, BundledOpened, } from "./skills-loader.js";
|
|
36
|
+
export { partialChunk, loopEventToChunk, chunkToDelta, toCoreOutput } from "./stream.js";
|
|
37
|
+
export type { StreamChunk } from "./stream.js";
|
|
38
|
+
export { startAgentSpan, NOOP_SPAN } from "./trace.js";
|
|
39
|
+
export type { SpanSink, AgentGenerateAttributes, AgentGenerateContext, AgentGenerateEvent } from "./trace.js";
|
|
40
|
+
export { frameGroundingAsData, frameToolResultAsData, collectProvenance } from "./safety.js";
|
|
41
|
+
export type { GroundedContext, GroundedFact, Provenance } from "./safety.js";
|
|
42
|
+
export { toAgentTurn, turnModelString } from "./request.js";
|
|
43
|
+
export type { AgentTurn, AgentTool, TraceContext } from "./request.js";
|
|
44
|
+
export { AgentProviderRef } from "./tokens.js";
|
|
45
|
+
/** Package version marker (pre-alpha). */
|
|
46
|
+
export declare const VERSION = "0.0.0";
|
|
47
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,eAAe,MAAM,CAAC;AAGtB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACpH,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC7D,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,GACZ,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG7D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACtF,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAGpE,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpF,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAOtF,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,SAAS,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,aAAa,GACd,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzF,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,YAAY,EAAE,QAAQ,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAG9G,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC7F,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,0CAA0C;AAC1C,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk — the default AgentProvider, backed by the Vercel AI SDK v6
|
|
3
|
+
* (+ AI Gateway, hosted-first). It implements the vendor-free `AgentProvider` contract owned by
|
|
4
|
+
* @cloc/core (generate/stream), routes hosted-first through the AI Gateway, and ends in a
|
|
5
|
+
* validated structured Output (`Output.object` + Zod) that is the json-render UI plan / IR.
|
|
6
|
+
*
|
|
7
|
+
* This package is the ONLY place `ai` (the Vercel AI SDK) is imported — @cloc/core carries no
|
|
8
|
+
* vendor edge (§34, §43 Listing 15; FR-002, Constitution Principle 8). Future siblings under
|
|
9
|
+
* packages/plugins: provider-ai-langchain, provider-ai-claude, provider-ai-open-ai (§34).
|
|
10
|
+
*
|
|
11
|
+
* The default export is the `definePlugin(...)` value the kernel loads; the named exports expose
|
|
12
|
+
* the Agent + its typed surface for hosts and tests.
|
|
13
|
+
*/
|
|
14
|
+
import { plugin } from "./plugin.js";
|
|
15
|
+
// The plugin value the kernel discovers + loads (provides the AgentProvider token; FR-001).
|
|
16
|
+
export default plugin;
|
|
17
|
+
// --- The Agent + its boot surface ---
|
|
18
|
+
export { plugin, agentProvider, agentDepsFromContext, declaredNeeds, PLUGIN_NAME, GATEWAY_HOST } from "./plugin.js";
|
|
19
|
+
export { AiSdkAgent, defaultRepairPrompt } from "./agent.js";
|
|
20
|
+
// --- Config / secrets surface (declarative selection; secret-by-name) ---
|
|
21
|
+
export { parseAgentConfig, AgentConfigSchema, modelChain, modelFieldToString, DEFAULT_REPAIR_POLICY, PROVIDER_ID, } from "./config.js";
|
|
22
|
+
export { needsFor, resolveGatewayKey, assertNoInlineSecret } from "./secrets.js";
|
|
23
|
+
// --- Gateway routing / failover + the surfaced error ---
|
|
24
|
+
export { resolveGateway, withFailover, AgentError, isAbortError } from "./gateway.js";
|
|
25
|
+
// --- Structured Output + validate/repair ---
|
|
26
|
+
export { outputSpecFor, makeStructuredOutput } from "./output.js";
|
|
27
|
+
export { validateOrRepair, validateOnce, ISSUE_SUMMARY_LIMIT } from "./validate.js";
|
|
28
|
+
// --- Render-time agentic primitives: the budgeted ToolLoopAgent runner (027-agentic-primitives) ---
|
|
29
|
+
// The render Agent runs a budgeted AI SDK 6 ToolLoopAgent (stopWhen / prepareStep) that surfaces
|
|
30
|
+
// Skills + Memory + Tools from GenOpts (§16b). Skills load by three-level progressive disclosure;
|
|
31
|
+
// Memory is the Anthropic memory-tool interface backed by an unstorage driver; every tool/skill/
|
|
32
|
+
// memory access clears the §58 gate before execution (FR-014, FR-021).
|
|
33
|
+
export { buildToolSet, buildAgenticToolSet, stopAfter, toAiStopWhen, toAiPrepareStep, DEFAULT_MAX_STEPS, } from "./tool-loop.js";
|
|
34
|
+
export { unstorageMemoryStore, buildMemoryTools, MEMORY_ROOT, MEMORY_TOOL_NAMES, } from "./memory-tool.js";
|
|
35
|
+
export { skillMetadata, frameSkillsForPrompt, activateSkill, openBundled, } from "./skills-loader.js";
|
|
36
|
+
// --- Streaming (partial-object parse-and-heal) + trace subtree ---
|
|
37
|
+
export { partialChunk, loopEventToChunk, chunkToDelta, toCoreOutput } from "./stream.js";
|
|
38
|
+
export { startAgentSpan, NOOP_SPAN } from "./trace.js";
|
|
39
|
+
// --- Safety (data-not-instructions) + request normalization ---
|
|
40
|
+
export { frameGroundingAsData, frameToolResultAsData, collectProvenance } from "./safety.js";
|
|
41
|
+
export { toAgentTurn, turnModelString } from "./request.js";
|
|
42
|
+
// --- The token this plugin answers (re-exported for hosts/tests) ---
|
|
43
|
+
export { AgentProviderRef } from "./tokens.js";
|
|
44
|
+
/** Package version marker (pre-alpha). */
|
|
45
|
+
export const VERSION = "0.0.0";
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,4FAA4F;AAC5F,eAAe,MAAM,CAAC;AAEtB,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,oBAAoB,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEpH,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAG7D,2EAA2E;AAC3E,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,qBAAqB,EACrB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAGjF,0DAA0D;AAC1D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGtF,8CAA8C;AAC9C,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGpF,qGAAqG;AACrG,iGAAiG;AACjG,kGAAkG;AAClG,iGAAiG;AACjG,uEAAuE;AACvE,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,aAAa,EACb,WAAW,GACZ,MAAM,oBAAoB,CAAC;AAU5B,oEAAoE;AACpE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvD,iEAAiE;AACjE,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE7F,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG5D,sEAAsE;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,0CAA0C;AAC1C,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @cloc/provider-ai-sdk · memory-tool.ts — the Anthropic Memory-tool interface, backed by Cloc's
|
|
3
|
+
* `unstorage` driver and joined to the render tool loop (027-agentic-primitives §16b.2; FR-007,
|
|
4
|
+
* FR-008, FR-009, FR-014, Principle 5).
|
|
5
|
+
*
|
|
6
|
+
* Memory is the Agent's per-site durable scratch/recall at `.cloc/memory/`. The model drives
|
|
7
|
+
* create/read/update/delete over a `/memory` path that persists across sessions; Cloc OWNS where
|
|
8
|
+
* the bytes live by backing the tool with a swappable `unstorage` driver (FS / Redis / KV, §43), so
|
|
9
|
+
* the SAME memory persists across runtimes (FR-008). The contract shape (`MemoryStore`) is owned by
|
|
10
|
+
* @cloc/core; this module wires the driver edge + exposes the CRUD as AI-SDK tools.
|
|
11
|
+
*
|
|
12
|
+
* Two surfaces:
|
|
13
|
+
* 1. {@link unstorageMemoryStore} — turn an `unstorage` instance into a vendor-free `MemoryStore`.
|
|
14
|
+
* 2. {@link buildMemoryTools} — expose that store to the loop as AI-SDK `tool()` defs the model
|
|
15
|
+
* drives. EVERY access clears the §58 gate BEFORE the read/write (FR-014); memory CONTENTS are
|
|
16
|
+
* DATA — the system MUST NOT execute instructions injected through them (Principle 5).
|
|
17
|
+
*
|
|
18
|
+
* Memory ≠ grounding (FR-009): this is recall, not RAG over the data repo (that stays the separate
|
|
19
|
+
* `GroundingProvider`). Memory ≠ `state.json` (machine A/B outcomes) ≠ `journal/` (human teaching).
|
|
20
|
+
*
|
|
21
|
+
* TODO(027/Governance, NEEDS CLARIFICATION): committed vs `.gitignore`d, and per-route/site/tenant
|
|
22
|
+
* scope of `.cloc/memory/`. §16b.2 says per-site/versioned; the privacy implication of committing
|
|
23
|
+
* model-written memory is unresolved. Routed to Governance — does not change this wiring.
|
|
24
|
+
*/
|
|
25
|
+
import type { ToolSet as AiToolSet } from "ai";
|
|
26
|
+
import type { MemoryStore, MemoryBackend, PolicyGateHook } from "./tokens.js";
|
|
27
|
+
import type { LoopEvent } from "./tool-loop.js";
|
|
28
|
+
/** The mount root for memory under the data repo (`.cloc/memory/`), §16b.2. */
|
|
29
|
+
export declare const MEMORY_ROOT = ".cloc/memory/";
|
|
30
|
+
/**
|
|
31
|
+
* The minimal `unstorage` surface this module needs — modeled STRUCTURALLY so the runner is not
|
|
32
|
+
* forced to import a concrete driver across the public signature. A real `unstorage` `Storage`
|
|
33
|
+
* instance (from `createStorage({ driver })`) satisfies it; tests pass an in-memory stand-in.
|
|
34
|
+
* Cloc owns the driver choice (FS / Redis / KV), so the same memory persists across runtimes (§43).
|
|
35
|
+
*/
|
|
36
|
+
export interface UnstorageLike {
|
|
37
|
+
getItem(key: string): Promise<unknown>;
|
|
38
|
+
setItem(key: string, value: string): Promise<void>;
|
|
39
|
+
removeItem(key: string): Promise<void>;
|
|
40
|
+
getKeys(base?: string): Promise<string[]>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Adapt an `unstorage` instance to the vendor-free {@link MemoryStore} (the memory-tool interface).
|
|
44
|
+
* Paths are normalized under a single namespace so the bytes live wherever the injected driver puts
|
|
45
|
+
* them (FR-008). `read` returns `null` for a missing note; `write` creates or overwrites.
|
|
46
|
+
*/
|
|
47
|
+
export declare function unstorageMemoryStore(storage: UnstorageLike, backend?: MemoryBackend): MemoryStore;
|
|
48
|
+
/**
|
|
49
|
+
* The set of memory operations exposed to the model as AI-SDK tools, each GATED. The model invokes
|
|
50
|
+
* `memory.read` / `memory.write` / `memory.update` / `memory.delete` / `memory.list` over a
|
|
51
|
+
* `/memory` path; the tool's `execute` clears the §58 gate BEFORE touching the store and frames the
|
|
52
|
+
* result as DATA before it re-enters the loop (FR-014, Principle 5).
|
|
53
|
+
*/
|
|
54
|
+
export declare const MEMORY_TOOL_NAMES: readonly ["memory.read", "memory.write", "memory.update", "memory.delete", "memory.list"];
|
|
55
|
+
/**
|
|
56
|
+
* Build the gated AI-SDK memory tool set the model drives. EVERY op clears `gate.check({ kind:
|
|
57
|
+
* 'memory', op, path })` BEFORE the store is touched; a denial DEGRADES (returns an attributable
|
|
58
|
+
* data block, never throws, never bypasses — FR-014, FR-021). Results re-enter the loop as DATA
|
|
59
|
+
* (frameToolResultAsData), so an injected "ignore previous instructions…" note is observed, never
|
|
60
|
+
* executed (Principle 5). Returns `{}` when no memory is enabled (FR-002, zero-cost baseline).
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildMemoryTools(memory: MemoryStore | undefined, gate: PolicyGateHook, onEvent: (event: LoopEvent) => void): AiToolSet;
|
|
63
|
+
//# sourceMappingURL=memory-tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-tool.d.ts","sourceRoot":"","sources":["../src/memory-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,OAAO,IAAI,SAAS,EAAkB,MAAM,IAAI,CAAC;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAY,cAAc,EAAE,MAAM,aAAa,CAAC;AAExF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,+EAA+E;AAC/E,eAAO,MAAM,WAAW,kBAAkB,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,aAAa,GACtB,WAAW,CA4Bb;AAsBD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,2FAMpB,CAAC;AA4BX;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,GAClC,SAAS,CA8DX"}
|