@graphorin/provider 0.5.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 +6 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.js +6 -0
- package/dist/adapters/llamacpp-server.d.ts +69 -0
- package/dist/adapters/llamacpp-server.d.ts.map +1 -0
- package/dist/adapters/llamacpp-server.js +51 -0
- package/dist/adapters/llamacpp-server.js.map +1 -0
- package/dist/adapters/ollama.d.ts +43 -0
- package/dist/adapters/ollama.d.ts.map +1 -0
- package/dist/adapters/ollama.js +246 -0
- package/dist/adapters/ollama.js.map +1 -0
- package/dist/adapters/openai-compatible.d.ts +48 -0
- package/dist/adapters/openai-compatible.d.ts.map +1 -0
- package/dist/adapters/openai-compatible.js +28 -0
- package/dist/adapters/openai-compatible.js.map +1 -0
- package/dist/adapters/vercel.d.ts +135 -0
- package/dist/adapters/vercel.d.ts.map +1 -0
- package/dist/adapters/vercel.js +306 -0
- package/dist/adapters/vercel.js.map +1 -0
- package/dist/counters/anthropic.d.ts +36 -0
- package/dist/counters/anthropic.d.ts.map +1 -0
- package/dist/counters/anthropic.js +63 -0
- package/dist/counters/anthropic.js.map +1 -0
- package/dist/counters/bedrock.d.ts +27 -0
- package/dist/counters/bedrock.d.ts.map +1 -0
- package/dist/counters/bedrock.js +29 -0
- package/dist/counters/bedrock.js.map +1 -0
- package/dist/counters/dispatcher.d.ts +34 -0
- package/dist/counters/dispatcher.d.ts.map +1 -0
- package/dist/counters/dispatcher.js +78 -0
- package/dist/counters/dispatcher.js.map +1 -0
- package/dist/counters/global.d.ts +26 -0
- package/dist/counters/global.d.ts.map +1 -0
- package/dist/counters/global.js +31 -0
- package/dist/counters/global.js.map +1 -0
- package/dist/counters/google.d.ts +27 -0
- package/dist/counters/google.d.ts.map +1 -0
- package/dist/counters/google.js +29 -0
- package/dist/counters/google.js.map +1 -0
- package/dist/counters/heuristic.d.ts +37 -0
- package/dist/counters/heuristic.d.ts.map +1 -0
- package/dist/counters/heuristic.js +64 -0
- package/dist/counters/heuristic.js.map +1 -0
- package/dist/counters/index.d.ts +9 -0
- package/dist/counters/index.js +10 -0
- package/dist/counters/js-tiktoken.d.ts +63 -0
- package/dist/counters/js-tiktoken.d.ts.map +1 -0
- package/dist/counters/js-tiktoken.js +73 -0
- package/dist/counters/js-tiktoken.js.map +1 -0
- package/dist/counters/serialize.d.ts +37 -0
- package/dist/counters/serialize.d.ts.map +1 -0
- package/dist/counters/serialize.js +57 -0
- package/dist/counters/serialize.js.map +1 -0
- package/dist/errors/errors.d.ts +167 -0
- package/dist/errors/errors.d.ts.map +1 -0
- package/dist/errors/errors.js +182 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +3 -0
- package/dist/index.d.ts +69 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/abort.js +34 -0
- package/dist/internal/abort.js.map +1 -0
- package/dist/internal/http.js +163 -0
- package/dist/internal/http.js.map +1 -0
- package/dist/internal/openai-shaped.js +308 -0
- package/dist/internal/openai-shaped.js.map +1 -0
- package/dist/internal/sse.js +104 -0
- package/dist/internal/sse.js.map +1 -0
- package/dist/internal/url-utils.js +24 -0
- package/dist/internal/url-utils.js.map +1 -0
- package/dist/middleware/compose.d.ts +85 -0
- package/dist/middleware/compose.d.ts.map +1 -0
- package/dist/middleware/compose.js +174 -0
- package/dist/middleware/compose.js.map +1 -0
- package/dist/middleware/index.d.ts +10 -0
- package/dist/middleware/index.js +11 -0
- package/dist/middleware/production-hook.d.ts +27 -0
- package/dist/middleware/production-hook.d.ts.map +1 -0
- package/dist/middleware/production-hook.js +21 -0
- package/dist/middleware/production-hook.js.map +1 -0
- package/dist/middleware/with-cost-limit.d.ts +46 -0
- package/dist/middleware/with-cost-limit.d.ts.map +1 -0
- package/dist/middleware/with-cost-limit.js +66 -0
- package/dist/middleware/with-cost-limit.js.map +1 -0
- package/dist/middleware/with-cost-tracking.d.ts +91 -0
- package/dist/middleware/with-cost-tracking.d.ts.map +1 -0
- package/dist/middleware/with-cost-tracking.js +95 -0
- package/dist/middleware/with-cost-tracking.js.map +1 -0
- package/dist/middleware/with-fallback.d.ts +25 -0
- package/dist/middleware/with-fallback.d.ts.map +1 -0
- package/dist/middleware/with-fallback.js +84 -0
- package/dist/middleware/with-fallback.js.map +1 -0
- package/dist/middleware/with-rate-limit.d.ts +36 -0
- package/dist/middleware/with-rate-limit.d.ts.map +1 -0
- package/dist/middleware/with-rate-limit.js +141 -0
- package/dist/middleware/with-rate-limit.js.map +1 -0
- package/dist/middleware/with-redaction.d.ts +60 -0
- package/dist/middleware/with-redaction.d.ts.map +1 -0
- package/dist/middleware/with-redaction.js +305 -0
- package/dist/middleware/with-redaction.js.map +1 -0
- package/dist/middleware/with-retry.d.ts +26 -0
- package/dist/middleware/with-retry.d.ts.map +1 -0
- package/dist/middleware/with-retry.js +157 -0
- package/dist/middleware/with-retry.js.map +1 -0
- package/dist/middleware/with-tracing.d.ts +21 -0
- package/dist/middleware/with-tracing.d.ts.map +1 -0
- package/dist/middleware/with-tracing.js +55 -0
- package/dist/middleware/with-tracing.js.map +1 -0
- package/dist/model-tier/classify.d.ts +34 -0
- package/dist/model-tier/classify.d.ts.map +1 -0
- package/dist/model-tier/classify.js +117 -0
- package/dist/model-tier/classify.js.map +1 -0
- package/dist/model-tier/index.d.ts +2 -0
- package/dist/model-tier/index.js +3 -0
- package/dist/provider.d.ts +51 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +64 -0
- package/dist/provider.js.map +1 -0
- package/dist/reasoning/apply-policy.d.ts +22 -0
- package/dist/reasoning/apply-policy.d.ts.map +1 -0
- package/dist/reasoning/apply-policy.js +47 -0
- package/dist/reasoning/apply-policy.js.map +1 -0
- package/dist/reasoning/classify-contract.d.ts +41 -0
- package/dist/reasoning/classify-contract.d.ts.map +1 -0
- package/dist/reasoning/classify-contract.js +59 -0
- package/dist/reasoning/classify-contract.js.map +1 -0
- package/dist/reasoning/index.d.ts +4 -0
- package/dist/reasoning/index.js +5 -0
- package/dist/reasoning/retention.d.ts +39 -0
- package/dist/reasoning/retention.d.ts.map +1 -0
- package/dist/reasoning/retention.js +33 -0
- package/dist/reasoning/retention.js.map +1 -0
- package/dist/tool-examples.d.ts +14 -0
- package/dist/tool-examples.d.ts.map +1 -0
- package/dist/tool-examples.js +35 -0
- package/dist/tool-examples.js.map +1 -0
- package/dist/trust/classify-local-provider.d.ts +47 -0
- package/dist/trust/classify-local-provider.d.ts.map +1 -0
- package/dist/trust/classify-local-provider.js +164 -0
- package/dist/trust/classify-local-provider.js.map +1 -0
- package/dist/trust/index.d.ts +3 -0
- package/dist/trust/index.js +3 -0
- package/package.json +128 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/reasoning/retention.ts
|
|
2
|
+
/**
|
|
3
|
+
* Map from `ReasoningContract` to the conservative default
|
|
4
|
+
* `ReasoningRetention` value used when no override is supplied.
|
|
5
|
+
*
|
|
6
|
+
* @stable
|
|
7
|
+
*/
|
|
8
|
+
const REASONING_RETENTION_DEFAULTS = Object.freeze({
|
|
9
|
+
hidden: "strip",
|
|
10
|
+
"round-trip-required": "pass-through-claude",
|
|
11
|
+
optional: "strip"
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the effective {@link ReasoningRetention} value for a single
|
|
15
|
+
* request. The resolution is precedence-driven:
|
|
16
|
+
*
|
|
17
|
+
* 1. `requested` wins if defined.
|
|
18
|
+
* 2. `overridden` wins next.
|
|
19
|
+
* 3. The default for `contract` is used if the contract is known.
|
|
20
|
+
* 4. `'strip'` is the conservative fallback when no input is supplied.
|
|
21
|
+
*
|
|
22
|
+
* @stable
|
|
23
|
+
*/
|
|
24
|
+
function resolveReasoningRetention(input) {
|
|
25
|
+
if (input.requested !== void 0) return input.requested;
|
|
26
|
+
if (input.overridden !== void 0) return input.overridden;
|
|
27
|
+
if (input.contract !== void 0) return REASONING_RETENTION_DEFAULTS[input.contract];
|
|
28
|
+
return "strip";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { REASONING_RETENTION_DEFAULTS, resolveReasoningRetention };
|
|
33
|
+
//# sourceMappingURL=retention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retention.js","names":["REASONING_RETENTION_DEFAULTS: Readonly<Record<ReasoningContract, ReasoningRetention>>"],"sources":["../../src/reasoning/retention.ts"],"sourcesContent":["/**\n * Reasoning-retention resolver — picks the effective\n * {@link ReasoningRetention} value for a request given:\n *\n * 1. an explicit per-request `reasoningRetention` field (highest\n * precedence — user override always wins),\n * 2. an instance-level override supplied to `createProvider({...})`,\n * and\n * 3. the auto-detected default derived from the adapter's declared\n * `capabilities.reasoningContract` (lowest precedence).\n *\n * @packageDocumentation\n */\n\nimport type { ReasoningContract, ReasoningRetention } from '@graphorin/core';\n\n/**\n * Map from `ReasoningContract` to the conservative default\n * `ReasoningRetention` value used when no override is supplied.\n *\n * @stable\n */\nexport const REASONING_RETENTION_DEFAULTS: Readonly<Record<ReasoningContract, ReasoningRetention>> =\n Object.freeze({\n hidden: 'strip',\n 'round-trip-required': 'pass-through-claude',\n optional: 'strip',\n });\n\n/**\n * Inputs to {@link resolveReasoningRetention}.\n *\n * @stable\n */\nexport interface ResolveReasoningRetentionInput {\n /** Explicit per-request override (highest precedence). */\n readonly requested?: ReasoningRetention;\n /** Instance-level override supplied to `createProvider({...})`. */\n readonly overridden?: ReasoningRetention;\n /** Adapter-declared capability (lowest precedence). */\n readonly contract?: ReasoningContract;\n}\n\n/**\n * Resolve the effective {@link ReasoningRetention} value for a single\n * request. The resolution is precedence-driven:\n *\n * 1. `requested` wins if defined.\n * 2. `overridden` wins next.\n * 3. The default for `contract` is used if the contract is known.\n * 4. `'strip'` is the conservative fallback when no input is supplied.\n *\n * @stable\n */\nexport function resolveReasoningRetention(\n input: ResolveReasoningRetentionInput,\n): ReasoningRetention {\n if (input.requested !== undefined) return input.requested;\n if (input.overridden !== undefined) return input.overridden;\n if (input.contract !== undefined) {\n return REASONING_RETENTION_DEFAULTS[input.contract];\n }\n return 'strip';\n}\n"],"mappings":";;;;;;;AAsBA,MAAaA,+BACX,OAAO,OAAO;CACZ,QAAQ;CACR,uBAAuB;CACvB,UAAU;CACX,CAAC;;;;;;;;;;;;AA2BJ,SAAgB,0BACd,OACoB;AACpB,KAAI,MAAM,cAAc,OAAW,QAAO,MAAM;AAChD,KAAI,MAAM,eAAe,OAAW,QAAO,MAAM;AACjD,KAAI,MAAM,aAAa,OACrB,QAAO,6BAA6B,MAAM;AAE5C,QAAO"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ToolDefinition } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/tool-examples.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Fold each tool's `examples` into its `description` and drop the structured
|
|
7
|
+
* field. Non-destructive: a tool with no examples is returned by reference, and
|
|
8
|
+
* the whole array is returned unchanged (same reference) when nothing folds — so
|
|
9
|
+
* callers can cheaply detect a no-op.
|
|
10
|
+
*/
|
|
11
|
+
declare function foldToolExamples(tools: ReadonlyArray<ToolDefinition>): ReadonlyArray<ToolDefinition>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { foldToolExamples };
|
|
14
|
+
//# sourceMappingURL=tool-examples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-examples.d.ts","names":[],"sources":["../src/tool-examples.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;iBA8BgB,gBAAA,QACP,cAAc,kBACpB,cAAc"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/tool-examples.ts
|
|
2
|
+
/** Render worked examples as a compact, deterministic text block. */
|
|
3
|
+
function renderExamplesSection(examples) {
|
|
4
|
+
return `Examples:\n${examples.map((ex, i) => {
|
|
5
|
+
const comment = ex.comment !== void 0 ? ` // ${ex.comment}` : "";
|
|
6
|
+
return `${i + 1}. input: ${JSON.stringify(ex.input)} -> output: ${JSON.stringify(ex.output)}${comment}`;
|
|
7
|
+
}).join("\n")}`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Fold each tool's `examples` into its `description` and drop the structured
|
|
11
|
+
* field. Non-destructive: a tool with no examples is returned by reference, and
|
|
12
|
+
* the whole array is returned unchanged (same reference) when nothing folds — so
|
|
13
|
+
* callers can cheaply detect a no-op.
|
|
14
|
+
*/
|
|
15
|
+
function foldToolExamples(tools) {
|
|
16
|
+
let changed = false;
|
|
17
|
+
const out = tools.map((tool) => {
|
|
18
|
+
const examples = tool.examples;
|
|
19
|
+
if (examples === void 0 || examples.length === 0) return tool;
|
|
20
|
+
changed = true;
|
|
21
|
+
const section = renderExamplesSection(examples);
|
|
22
|
+
const description = tool.description !== void 0 && tool.description.length > 0 ? `${tool.description}\n\n${section}` : section;
|
|
23
|
+
return {
|
|
24
|
+
name: tool.name,
|
|
25
|
+
inputSchema: tool.inputSchema,
|
|
26
|
+
description,
|
|
27
|
+
...tool.outputSchema !== void 0 ? { outputSchema: tool.outputSchema } : {}
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
return changed ? out : tools;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { foldToolExamples };
|
|
35
|
+
//# sourceMappingURL=tool-examples.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-examples.js","names":[],"sources":["../src/tool-examples.ts"],"sourcesContent":["/**\n * A1 (SOTA): fold a tool's worked `examples` into its model-facing description.\n *\n * `ToolDefinition` already carries `examples` on the wire (the agent projects\n * them from `Tool.examples`), and the contract notes implementations MAY fold\n * them into the description — but no adapter did, so the model never saw them.\n * Anthropic reports complex-parameter accuracy jumps 72% → 90% with worked\n * examples in the tool text. This renders them deterministically (so the tool\n * spec stays prompt-cache-stable) and drops the now-redundant structured field.\n *\n * @packageDocumentation\n */\n\nimport type { ToolDefinition, ToolDefinitionExample } from '@graphorin/core';\n\n/** Render worked examples as a compact, deterministic text block. */\nfunction renderExamplesSection(examples: ReadonlyArray<ToolDefinitionExample>): string {\n const lines = examples.map((ex, i) => {\n const comment = ex.comment !== undefined ? ` // ${ex.comment}` : '';\n return `${i + 1}. input: ${JSON.stringify(ex.input)} -> output: ${JSON.stringify(ex.output)}${comment}`;\n });\n return `Examples:\\n${lines.join('\\n')}`;\n}\n\n/**\n * Fold each tool's `examples` into its `description` and drop the structured\n * field. Non-destructive: a tool with no examples is returned by reference, and\n * the whole array is returned unchanged (same reference) when nothing folds — so\n * callers can cheaply detect a no-op.\n */\nexport function foldToolExamples(\n tools: ReadonlyArray<ToolDefinition>,\n): ReadonlyArray<ToolDefinition> {\n let changed = false;\n const out = tools.map((tool): ToolDefinition => {\n const examples = tool.examples;\n if (examples === undefined || examples.length === 0) return tool;\n changed = true;\n const section = renderExamplesSection(examples);\n const description =\n tool.description !== undefined && tool.description.length > 0\n ? `${tool.description}\\n\\n${section}`\n : section;\n // Rebuild without `examples` (now in the description text), preserving every\n // other field — notably `outputSchema` (A5).\n return {\n name: tool.name,\n inputSchema: tool.inputSchema,\n description,\n ...(tool.outputSchema !== undefined ? { outputSchema: tool.outputSchema } : {}),\n };\n });\n return changed ? out : tools;\n}\n"],"mappings":";;AAgBA,SAAS,sBAAsB,UAAwD;AAKrF,QAAO,cAJO,SAAS,KAAK,IAAI,MAAM;EACpC,MAAM,UAAU,GAAG,YAAY,SAAY,QAAQ,GAAG,YAAY;AAClE,SAAO,GAAG,IAAI,EAAE,WAAW,KAAK,UAAU,GAAG,MAAM,CAAC,cAAc,KAAK,UAAU,GAAG,OAAO,GAAG;GAC9F,CACyB,KAAK,KAAK;;;;;;;;AASvC,SAAgB,iBACd,OAC+B;CAC/B,IAAI,UAAU;CACd,MAAM,MAAM,MAAM,KAAK,SAAyB;EAC9C,MAAM,WAAW,KAAK;AACtB,MAAI,aAAa,UAAa,SAAS,WAAW,EAAG,QAAO;AAC5D,YAAU;EACV,MAAM,UAAU,sBAAsB,SAAS;EAC/C,MAAM,cACJ,KAAK,gBAAgB,UAAa,KAAK,YAAY,SAAS,IACxD,GAAG,KAAK,YAAY,MAAM,YAC1B;AAGN,SAAO;GACL,MAAM,KAAK;GACX,aAAa,KAAK;GAClB;GACA,GAAI,KAAK,iBAAiB,SAAY,EAAE,cAAc,KAAK,cAAc,GAAG,EAAE;GAC/E;GACD;AACF,QAAO,UAAU,MAAM"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LocalProviderTrust, Sensitivity } from "@graphorin/core";
|
|
2
|
+
|
|
3
|
+
//#region src/trust/classify-local-provider.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Result of {@link classifyLocalProvider}. Carries both the trust
|
|
7
|
+
* class and a short human-readable reason for the WARN log produced
|
|
8
|
+
* by the consuming adapter.
|
|
9
|
+
*
|
|
10
|
+
* @stable
|
|
11
|
+
*/
|
|
12
|
+
interface LocalProviderClassification {
|
|
13
|
+
readonly trust: LocalProviderTrust;
|
|
14
|
+
/** One-line reason — `'loopback IP 127.0.0.1'`, `'public IP 5.6.7.8 over HTTPS'`, ... */
|
|
15
|
+
readonly reason: string;
|
|
16
|
+
/** Default `acceptsSensitivity` for this trust class. */
|
|
17
|
+
readonly acceptsSensitivity: ReadonlyArray<Sensitivity>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Per-tier default sensitivity envelope. Lifted to a constant so
|
|
21
|
+
* downstream code (and tests) can import it without re-deriving the
|
|
22
|
+
* matrix.
|
|
23
|
+
*
|
|
24
|
+
* @stable
|
|
25
|
+
*/
|
|
26
|
+
declare const SENSITIVITY_DEFAULTS_PER_TRUST: Readonly<Record<LocalProviderTrust, ReadonlyArray<Sensitivity>>>;
|
|
27
|
+
/**
|
|
28
|
+
* Classify a URL string into one of the four {@link LocalProviderTrust}
|
|
29
|
+
* tiers. Throws `TypeError` if the URL is unparseable so adapters
|
|
30
|
+
* fail fast at construction time (programming error; not a runtime
|
|
31
|
+
* fault).
|
|
32
|
+
*
|
|
33
|
+
* @stable
|
|
34
|
+
*/
|
|
35
|
+
declare function classifyLocalProvider(baseUrl: string): LocalProviderClassification;
|
|
36
|
+
/**
|
|
37
|
+
* Permanent loopback classification used by in-process adapters
|
|
38
|
+
* (e.g. the `llamaCppNodeAdapter` companion package). Adapters that
|
|
39
|
+
* have no `baseUrl` declare this directly to make the source-of-truth
|
|
40
|
+
* symmetry obvious.
|
|
41
|
+
*
|
|
42
|
+
* @stable
|
|
43
|
+
*/
|
|
44
|
+
declare const PERMANENT_LOOPBACK_CLASSIFICATION: LocalProviderClassification;
|
|
45
|
+
//#endregion
|
|
46
|
+
export { LocalProviderClassification, PERMANENT_LOOPBACK_CLASSIFICATION, SENSITIVITY_DEFAULTS_PER_TRUST, classifyLocalProvider };
|
|
47
|
+
//# sourceMappingURL=classify-local-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-local-provider.d.ts","names":[],"sources":["../../src/trust/classify-local-provider.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;UA8BiB,2BAAA;kBACC;;;;+BAIa,cAAc;;;;;;;;;cAUhC,gCAAgC,SAC3C,OAAO,oBAAoB,cAAc;;;;;;;;;iBAgB3B,qBAAA,mBAAwC;;;;;;;;;cA2L3C,mCAAmC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
//#region src/trust/classify-local-provider.ts
|
|
2
|
+
/**
|
|
3
|
+
* Per-tier default sensitivity envelope. Lifted to a constant so
|
|
4
|
+
* downstream code (and tests) can import it without re-deriving the
|
|
5
|
+
* matrix.
|
|
6
|
+
*
|
|
7
|
+
* @stable
|
|
8
|
+
*/
|
|
9
|
+
const SENSITIVITY_DEFAULTS_PER_TRUST = Object.freeze({
|
|
10
|
+
loopback: Object.freeze([
|
|
11
|
+
"public",
|
|
12
|
+
"internal",
|
|
13
|
+
"secret"
|
|
14
|
+
]),
|
|
15
|
+
private: Object.freeze(["public", "internal"]),
|
|
16
|
+
"public-tls": Object.freeze(["public"]),
|
|
17
|
+
"public-cleartext": Object.freeze([])
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Classify a URL string into one of the four {@link LocalProviderTrust}
|
|
21
|
+
* tiers. Throws `TypeError` if the URL is unparseable so adapters
|
|
22
|
+
* fail fast at construction time (programming error; not a runtime
|
|
23
|
+
* fault).
|
|
24
|
+
*
|
|
25
|
+
* @stable
|
|
26
|
+
*/
|
|
27
|
+
function classifyLocalProvider(baseUrl) {
|
|
28
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0) throw new TypeError("classifyLocalProvider: baseUrl must be a non-empty string.");
|
|
29
|
+
if (baseUrl.startsWith("unix://") || baseUrl.startsWith("unix:/")) return {
|
|
30
|
+
trust: "loopback",
|
|
31
|
+
reason: `unix domain socket (${baseUrl})`,
|
|
32
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback
|
|
33
|
+
};
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(baseUrl);
|
|
37
|
+
} catch (cause) {
|
|
38
|
+
throw new TypeError(`classifyLocalProvider: baseUrl '${baseUrl}' is not a valid URL.`, { cause });
|
|
39
|
+
}
|
|
40
|
+
const protocol = url.protocol;
|
|
41
|
+
const hostname = url.hostname;
|
|
42
|
+
if (protocol !== "http:" && protocol !== "https:") return {
|
|
43
|
+
trust: "private",
|
|
44
|
+
reason: `non-HTTP protocol '${protocol}'`,
|
|
45
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private
|
|
46
|
+
};
|
|
47
|
+
const ipv4 = parseIpv4(hostname);
|
|
48
|
+
if (ipv4 !== null) {
|
|
49
|
+
if (isLoopbackIpv4(ipv4)) return {
|
|
50
|
+
trust: "loopback",
|
|
51
|
+
reason: `loopback IPv4 ${hostname}`,
|
|
52
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback
|
|
53
|
+
};
|
|
54
|
+
if (isPrivateIpv4(ipv4)) return {
|
|
55
|
+
trust: "private",
|
|
56
|
+
reason: `private IPv4 ${hostname}`,
|
|
57
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private
|
|
58
|
+
};
|
|
59
|
+
return classifyPublic(protocol, `public IPv4 ${hostname}`);
|
|
60
|
+
}
|
|
61
|
+
if (isIpv6(hostname)) {
|
|
62
|
+
if (isLoopbackIpv6(hostname)) return {
|
|
63
|
+
trust: "loopback",
|
|
64
|
+
reason: `loopback IPv6 ${hostname}`,
|
|
65
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback
|
|
66
|
+
};
|
|
67
|
+
if (isPrivateIpv6(hostname)) return {
|
|
68
|
+
trust: "private",
|
|
69
|
+
reason: `private IPv6 ${hostname}`,
|
|
70
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private
|
|
71
|
+
};
|
|
72
|
+
return classifyPublic(protocol, `public IPv6 ${hostname}`);
|
|
73
|
+
}
|
|
74
|
+
if (isLoopbackHostname(hostname)) return {
|
|
75
|
+
trust: "loopback",
|
|
76
|
+
reason: `loopback hostname '${hostname}'`,
|
|
77
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback
|
|
78
|
+
};
|
|
79
|
+
if (isPrivateHostnameSuffix(hostname)) return {
|
|
80
|
+
trust: "private",
|
|
81
|
+
reason: `private hostname suffix '${hostname}'`,
|
|
82
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private
|
|
83
|
+
};
|
|
84
|
+
return classifyPublic(protocol, `public hostname '${hostname}'`);
|
|
85
|
+
}
|
|
86
|
+
function classifyPublic(protocol, reason) {
|
|
87
|
+
if (protocol === "https:") return {
|
|
88
|
+
trust: "public-tls",
|
|
89
|
+
reason: `${reason} over HTTPS`,
|
|
90
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST["public-tls"]
|
|
91
|
+
};
|
|
92
|
+
return {
|
|
93
|
+
trust: "public-cleartext",
|
|
94
|
+
reason: `${reason} over HTTP`,
|
|
95
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST["public-cleartext"]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function parseIpv4(hostname) {
|
|
99
|
+
const match = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(hostname);
|
|
100
|
+
if (match === null) return null;
|
|
101
|
+
const a = Number(match[1]);
|
|
102
|
+
const b = Number(match[2]);
|
|
103
|
+
const c = Number(match[3]);
|
|
104
|
+
const d = Number(match[4]);
|
|
105
|
+
if (a > 255 || b > 255 || c > 255 || d > 255) return null;
|
|
106
|
+
return [
|
|
107
|
+
a,
|
|
108
|
+
b,
|
|
109
|
+
c,
|
|
110
|
+
d
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
function isLoopbackIpv4(ip) {
|
|
114
|
+
return ip[0] === 127;
|
|
115
|
+
}
|
|
116
|
+
function isPrivateIpv4(ip) {
|
|
117
|
+
if (ip[0] === 10) return true;
|
|
118
|
+
if (ip[0] === 192 && ip[1] === 168) return true;
|
|
119
|
+
if (ip[0] === 172 && ip[1] >= 16 && ip[1] <= 31) return true;
|
|
120
|
+
if (ip[0] === 100 && ip[1] >= 64 && ip[1] <= 127) return true;
|
|
121
|
+
if (ip[0] === 169 && ip[1] === 254) return true;
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
function isIpv6(hostname) {
|
|
125
|
+
return (hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname).includes(":");
|
|
126
|
+
}
|
|
127
|
+
function normaliseIpv6(hostname) {
|
|
128
|
+
return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
129
|
+
}
|
|
130
|
+
function isLoopbackIpv6(hostname) {
|
|
131
|
+
const norm = normaliseIpv6(hostname).toLowerCase();
|
|
132
|
+
return norm === "::1" || norm === "0:0:0:0:0:0:0:1";
|
|
133
|
+
}
|
|
134
|
+
function isPrivateIpv6(hostname) {
|
|
135
|
+
const norm = normaliseIpv6(hostname).toLowerCase();
|
|
136
|
+
if (norm.startsWith("fe80:") || norm.startsWith("fe8") || norm.startsWith("fe9") || norm.startsWith("fea") || norm.startsWith("feb")) return true;
|
|
137
|
+
if (norm.startsWith("fc") || norm.startsWith("fd")) return true;
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
function isLoopbackHostname(hostname) {
|
|
141
|
+
const lower = hostname.toLowerCase();
|
|
142
|
+
return lower === "localhost" || lower === "localhost.";
|
|
143
|
+
}
|
|
144
|
+
function isPrivateHostnameSuffix(hostname) {
|
|
145
|
+
const lower = hostname.toLowerCase();
|
|
146
|
+
return lower.endsWith(".local") || lower.endsWith(".lan") || lower.endsWith(".internal") || lower.endsWith(".home.arpa") || lower.endsWith(".intranet");
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Permanent loopback classification used by in-process adapters
|
|
150
|
+
* (e.g. the `llamaCppNodeAdapter` companion package). Adapters that
|
|
151
|
+
* have no `baseUrl` declare this directly to make the source-of-truth
|
|
152
|
+
* symmetry obvious.
|
|
153
|
+
*
|
|
154
|
+
* @stable
|
|
155
|
+
*/
|
|
156
|
+
const PERMANENT_LOOPBACK_CLASSIFICATION = Object.freeze({
|
|
157
|
+
trust: "loopback",
|
|
158
|
+
reason: "in-process adapter (no baseUrl)",
|
|
159
|
+
acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
//#endregion
|
|
163
|
+
export { PERMANENT_LOOPBACK_CLASSIFICATION, SENSITIVITY_DEFAULTS_PER_TRUST, classifyLocalProvider };
|
|
164
|
+
//# sourceMappingURL=classify-local-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify-local-provider.js","names":["SENSITIVITY_DEFAULTS_PER_TRUST: Readonly<\n Record<LocalProviderTrust, ReadonlyArray<Sensitivity>>\n>","url: URL","PERMANENT_LOOPBACK_CLASSIFICATION: LocalProviderClassification"],"sources":["../../src/trust/classify-local-provider.ts"],"sourcesContent":["/**\n * Shared trust classifier for every `baseUrl`-driven local-LLM\n * adapter. Emits one of four discriminant values per\n * {@link LocalProviderTrust}:\n *\n * - `'loopback'` — the URL points at the same host as the\n * running process (`localhost`, `127.0.0.0/8`, `::1`, or a\n * `unix:///path` socket).\n * - `'private'` — RFC 1918 / RFC 6598 / link-local /\n * multicast-DNS-style hostname.\n * - `'public-tls'` — public host AND `https://`.\n * - `'public-cleartext'` — public host AND `http://`.\n *\n * The dispatcher is a pure function: it sees the URL string and\n * nothing else. DNS resolution is deferred to the adapter layer\n * (cross-cut DEC-149 § DNS-rebinding mitigation), where the resolved\n * IP is re-classified on TTL expiry and the lowest-trust value wins.\n *\n * @packageDocumentation\n */\n\nimport type { LocalProviderTrust, Sensitivity } from '@graphorin/core';\n\n/**\n * Result of {@link classifyLocalProvider}. Carries both the trust\n * class and a short human-readable reason for the WARN log produced\n * by the consuming adapter.\n *\n * @stable\n */\nexport interface LocalProviderClassification {\n readonly trust: LocalProviderTrust;\n /** One-line reason — `'loopback IP 127.0.0.1'`, `'public IP 5.6.7.8 over HTTPS'`, ... */\n readonly reason: string;\n /** Default `acceptsSensitivity` for this trust class. */\n readonly acceptsSensitivity: ReadonlyArray<Sensitivity>;\n}\n\n/**\n * Per-tier default sensitivity envelope. Lifted to a constant so\n * downstream code (and tests) can import it without re-deriving the\n * matrix.\n *\n * @stable\n */\nexport const SENSITIVITY_DEFAULTS_PER_TRUST: Readonly<\n Record<LocalProviderTrust, ReadonlyArray<Sensitivity>>\n> = Object.freeze({\n loopback: Object.freeze(['public', 'internal', 'secret'] as const),\n private: Object.freeze(['public', 'internal'] as const),\n 'public-tls': Object.freeze(['public'] as const),\n 'public-cleartext': Object.freeze([] as const),\n});\n\n/**\n * Classify a URL string into one of the four {@link LocalProviderTrust}\n * tiers. Throws `TypeError` if the URL is unparseable so adapters\n * fail fast at construction time (programming error; not a runtime\n * fault).\n *\n * @stable\n */\nexport function classifyLocalProvider(baseUrl: string): LocalProviderClassification {\n if (typeof baseUrl !== 'string' || baseUrl.length === 0) {\n throw new TypeError('classifyLocalProvider: baseUrl must be a non-empty string.');\n }\n\n if (baseUrl.startsWith('unix://') || baseUrl.startsWith('unix:/')) {\n return {\n trust: 'loopback',\n reason: `unix domain socket (${baseUrl})`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback,\n };\n }\n\n let url: URL;\n try {\n url = new URL(baseUrl);\n } catch (cause) {\n throw new TypeError(`classifyLocalProvider: baseUrl '${baseUrl}' is not a valid URL.`, {\n cause,\n });\n }\n\n const protocol = url.protocol;\n const hostname = url.hostname;\n if (protocol !== 'http:' && protocol !== 'https:') {\n // Custom protocols (e.g. ws://) are out of scope for the four\n // bundled adapters; treat as private so a downstream WARN fires.\n return {\n trust: 'private',\n reason: `non-HTTP protocol '${protocol}'`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private,\n };\n }\n\n const ipv4 = parseIpv4(hostname);\n if (ipv4 !== null) {\n if (isLoopbackIpv4(ipv4)) {\n return {\n trust: 'loopback',\n reason: `loopback IPv4 ${hostname}`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback,\n };\n }\n if (isPrivateIpv4(ipv4)) {\n return {\n trust: 'private',\n reason: `private IPv4 ${hostname}`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private,\n };\n }\n return classifyPublic(protocol, `public IPv4 ${hostname}`);\n }\n\n if (isIpv6(hostname)) {\n if (isLoopbackIpv6(hostname)) {\n return {\n trust: 'loopback',\n reason: `loopback IPv6 ${hostname}`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback,\n };\n }\n if (isPrivateIpv6(hostname)) {\n return {\n trust: 'private',\n reason: `private IPv6 ${hostname}`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private,\n };\n }\n return classifyPublic(protocol, `public IPv6 ${hostname}`);\n }\n\n if (isLoopbackHostname(hostname)) {\n return {\n trust: 'loopback',\n reason: `loopback hostname '${hostname}'`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback,\n };\n }\n if (isPrivateHostnameSuffix(hostname)) {\n return {\n trust: 'private',\n reason: `private hostname suffix '${hostname}'`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.private,\n };\n }\n\n return classifyPublic(protocol, `public hostname '${hostname}'`);\n}\n\nfunction classifyPublic(protocol: string, reason: string): LocalProviderClassification {\n if (protocol === 'https:') {\n return {\n trust: 'public-tls',\n reason: `${reason} over HTTPS`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST['public-tls'],\n };\n }\n return {\n trust: 'public-cleartext',\n reason: `${reason} over HTTP`,\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST['public-cleartext'],\n };\n}\n\nfunction parseIpv4(hostname: string): [number, number, number, number] | null {\n const match = /^(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})$/.exec(hostname);\n if (match === null) return null;\n const a = Number(match[1]);\n const b = Number(match[2]);\n const c = Number(match[3]);\n const d = Number(match[4]);\n if (a > 255 || b > 255 || c > 255 || d > 255) return null;\n return [a, b, c, d];\n}\n\nfunction isLoopbackIpv4(ip: readonly [number, number, number, number]): boolean {\n return ip[0] === 127;\n}\n\nfunction isPrivateIpv4(ip: readonly [number, number, number, number]): boolean {\n // RFC 1918\n if (ip[0] === 10) return true;\n if (ip[0] === 192 && ip[1] === 168) return true;\n if (ip[0] === 172 && ip[1] >= 16 && ip[1] <= 31) return true;\n // RFC 6598 (CGNAT — Tailscale-friendly)\n if (ip[0] === 100 && ip[1] >= 64 && ip[1] <= 127) return true;\n // Link-local\n if (ip[0] === 169 && ip[1] === 254) return true;\n return false;\n}\n\nfunction isIpv6(hostname: string): boolean {\n const stripped =\n hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n return stripped.includes(':');\n}\n\nfunction normaliseIpv6(hostname: string): string {\n return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname;\n}\n\nfunction isLoopbackIpv6(hostname: string): boolean {\n const norm = normaliseIpv6(hostname).toLowerCase();\n return norm === '::1' || norm === '0:0:0:0:0:0:0:1';\n}\n\nfunction isPrivateIpv6(hostname: string): boolean {\n const norm = normaliseIpv6(hostname).toLowerCase();\n // Link-local fe80::/10\n if (\n norm.startsWith('fe80:') ||\n norm.startsWith('fe8') ||\n norm.startsWith('fe9') ||\n norm.startsWith('fea') ||\n norm.startsWith('feb')\n ) {\n return true;\n }\n // Unique local fc00::/7 (covers fc:: and fd::)\n if (norm.startsWith('fc') || norm.startsWith('fd')) return true;\n return false;\n}\n\nfunction isLoopbackHostname(hostname: string): boolean {\n const lower = hostname.toLowerCase();\n return lower === 'localhost' || lower === 'localhost.';\n}\n\nfunction isPrivateHostnameSuffix(hostname: string): boolean {\n const lower = hostname.toLowerCase();\n return (\n lower.endsWith('.local') ||\n lower.endsWith('.lan') ||\n lower.endsWith('.internal') ||\n lower.endsWith('.home.arpa') ||\n lower.endsWith('.intranet')\n );\n}\n\n/**\n * Permanent loopback classification used by in-process adapters\n * (e.g. the `llamaCppNodeAdapter` companion package). Adapters that\n * have no `baseUrl` declare this directly to make the source-of-truth\n * symmetry obvious.\n *\n * @stable\n */\nexport const PERMANENT_LOOPBACK_CLASSIFICATION: LocalProviderClassification = Object.freeze({\n trust: 'loopback',\n reason: 'in-process adapter (no baseUrl)',\n acceptsSensitivity: SENSITIVITY_DEFAULTS_PER_TRUST.loopback,\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { LocalProviderClassification, PERMANENT_LOOPBACK_CLASSIFICATION, SENSITIVITY_DEFAULTS_PER_TRUST, classifyLocalProvider } from "./classify-local-provider.js";
|
|
2
|
+
import { LocalProviderTrust, OllamaTrust } from "@graphorin/core";
|
|
3
|
+
export { type LocalProviderClassification, type LocalProviderTrust, type OllamaTrust, PERMANENT_LOOPBACK_CLASSIFICATION, SENSITIVITY_DEFAULTS_PER_TRUST, classifyLocalProvider };
|
package/package.json
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@graphorin/provider",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "Vendor-neutral LLM provider layer for the Graphorin framework. Ships the canonical Provider interface, the Vercel AI SDK adapter (default cloud path), three local-LLM adapters (direct Ollama HTTP, llama-server HTTP, and a generic OpenAI-compatible adapter for LMStudio / LocalAI / vLLM / Together-style endpoints), the shared LocalProviderTrust classifier (loopback / private / public-tls / public-cleartext), the canonical-order middleware composer (withTracing / withRetry / withRateLimit / withCostLimit / withCostTracking / withFallback / withRedaction), the pluggable TokenCounter dispatcher (js-tiktoken default plus per-vendor native counters and a heuristic fallback), the per-provider model-tier auto-classifier (fast / balanced / smart), and the production startup hook that fails fast when withRedaction is missing.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Oleksiy Stepurenko",
|
|
7
|
+
"homepage": "https://github.com/o-stepper/graphorin/tree/main/packages/provider",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/o-stepper/graphorin.git",
|
|
11
|
+
"directory": "packages/provider"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/o-stepper/graphorin/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"graphorin",
|
|
18
|
+
"ai",
|
|
19
|
+
"agents",
|
|
20
|
+
"framework",
|
|
21
|
+
"provider",
|
|
22
|
+
"llm",
|
|
23
|
+
"vercel-ai-sdk",
|
|
24
|
+
"ollama",
|
|
25
|
+
"llama-cpp",
|
|
26
|
+
"openai-compatible",
|
|
27
|
+
"middleware",
|
|
28
|
+
"retry",
|
|
29
|
+
"fallback",
|
|
30
|
+
"rate-limit",
|
|
31
|
+
"cost-limit",
|
|
32
|
+
"redaction",
|
|
33
|
+
"token-counter",
|
|
34
|
+
"tiktoken",
|
|
35
|
+
"local-first"
|
|
36
|
+
],
|
|
37
|
+
"type": "module",
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22.0.0"
|
|
40
|
+
},
|
|
41
|
+
"main": "./dist/index.js",
|
|
42
|
+
"module": "./dist/index.js",
|
|
43
|
+
"types": "./dist/index.d.ts",
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"import": "./dist/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./adapters/vercel": {
|
|
50
|
+
"types": "./dist/adapters/vercel.d.ts",
|
|
51
|
+
"import": "./dist/adapters/vercel.js"
|
|
52
|
+
},
|
|
53
|
+
"./adapters/ollama": {
|
|
54
|
+
"types": "./dist/adapters/ollama.d.ts",
|
|
55
|
+
"import": "./dist/adapters/ollama.js"
|
|
56
|
+
},
|
|
57
|
+
"./adapters/llamacpp-server": {
|
|
58
|
+
"types": "./dist/adapters/llamacpp-server.d.ts",
|
|
59
|
+
"import": "./dist/adapters/llamacpp-server.js"
|
|
60
|
+
},
|
|
61
|
+
"./adapters/openai-compatible": {
|
|
62
|
+
"types": "./dist/adapters/openai-compatible.d.ts",
|
|
63
|
+
"import": "./dist/adapters/openai-compatible.js"
|
|
64
|
+
},
|
|
65
|
+
"./middleware": {
|
|
66
|
+
"types": "./dist/middleware/index.d.ts",
|
|
67
|
+
"import": "./dist/middleware/index.js"
|
|
68
|
+
},
|
|
69
|
+
"./counters": {
|
|
70
|
+
"types": "./dist/counters/index.d.ts",
|
|
71
|
+
"import": "./dist/counters/index.js"
|
|
72
|
+
},
|
|
73
|
+
"./trust": {
|
|
74
|
+
"types": "./dist/trust/index.d.ts",
|
|
75
|
+
"import": "./dist/trust/index.js"
|
|
76
|
+
},
|
|
77
|
+
"./model-tier": {
|
|
78
|
+
"types": "./dist/model-tier/index.d.ts",
|
|
79
|
+
"import": "./dist/model-tier/index.js"
|
|
80
|
+
},
|
|
81
|
+
"./reasoning": {
|
|
82
|
+
"types": "./dist/reasoning/index.d.ts",
|
|
83
|
+
"import": "./dist/reasoning/index.js"
|
|
84
|
+
},
|
|
85
|
+
"./errors": {
|
|
86
|
+
"types": "./dist/errors/index.d.ts",
|
|
87
|
+
"import": "./dist/errors/index.js"
|
|
88
|
+
},
|
|
89
|
+
"./package.json": "./package.json"
|
|
90
|
+
},
|
|
91
|
+
"files": [
|
|
92
|
+
"dist",
|
|
93
|
+
"README.md",
|
|
94
|
+
"CHANGELOG.md",
|
|
95
|
+
"LICENSE"
|
|
96
|
+
],
|
|
97
|
+
"dependencies": {
|
|
98
|
+
"@graphorin/core": "0.5.0",
|
|
99
|
+
"@graphorin/observability": "0.5.0"
|
|
100
|
+
},
|
|
101
|
+
"peerDependencies": {
|
|
102
|
+
"ai": "^7.0.0-beta.76",
|
|
103
|
+
"js-tiktoken": "^1.0.0"
|
|
104
|
+
},
|
|
105
|
+
"peerDependenciesMeta": {
|
|
106
|
+
"ai": {
|
|
107
|
+
"optional": true
|
|
108
|
+
},
|
|
109
|
+
"js-tiktoken": {
|
|
110
|
+
"optional": true
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
"publishConfig": {
|
|
114
|
+
"access": "public",
|
|
115
|
+
"provenance": true
|
|
116
|
+
},
|
|
117
|
+
"devDependencies": {
|
|
118
|
+
"fast-check": "^3.23.0",
|
|
119
|
+
"js-tiktoken": "^1.0.21"
|
|
120
|
+
},
|
|
121
|
+
"scripts": {
|
|
122
|
+
"build": "tsdown",
|
|
123
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
124
|
+
"test": "vitest run",
|
|
125
|
+
"lint": "biome check .",
|
|
126
|
+
"clean": "rimraf dist .turbo *.tsbuildinfo"
|
|
127
|
+
}
|
|
128
|
+
}
|