@arnilo/prism 0.0.15 → 0.0.17
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 +31 -0
- package/dist/agent-definitions.js +2 -3
- package/dist/agent-loops.js +12 -7
- package/dist/agent-run-lifecycle.d.ts +1 -2
- package/dist/agent-run-lifecycle.js +1 -1
- package/dist/agent-run-state.js +29 -4
- package/dist/agents.d.ts +1 -1
- package/dist/agents.js +163 -61
- package/dist/cache-helpers.js +18 -9
- package/dist/checkpoints.d.ts +4 -0
- package/dist/checkpoints.js +17 -9
- package/dist/cli-init.js +3 -7
- package/dist/cli-runner.d.ts +2 -6
- package/dist/cli-runner.js +71 -33
- package/dist/compaction.js +5 -4
- package/dist/config.js +7 -4
- package/dist/content.js +26 -24
- package/dist/context-budget.js +18 -11
- package/dist/contracts.d.ts +16 -3
- package/dist/contracts.js +4 -1
- package/dist/contribution-parsing.js +6 -2
- package/dist/contributions.d.ts +2 -0
- package/dist/contributions.js +3 -0
- package/dist/conversations.js +2 -1
- package/dist/credentials.d.ts +8 -2
- package/dist/credentials.js +9 -3
- package/dist/event-multiplexer.js +18 -4
- package/dist/extensions.d.ts +7 -1
- package/dist/extensions.js +64 -6
- package/dist/feedback.js +12 -10
- package/dist/guardrails.d.ts +1 -1
- package/dist/guardrails.js +26 -17
- package/dist/identity.js +10 -2
- package/dist/index.d.ts +82 -83
- package/dist/index.js +42 -42
- package/dist/input.d.ts +2 -2
- package/dist/input.js +50 -27
- package/dist/instruction-injection.d.ts +1 -1
- package/dist/middleware.js +9 -1
- package/dist/models.d.ts +2 -0
- package/dist/models.js +3 -0
- package/dist/node/agent-definitions.js +16 -8
- package/dist/node/contribution-discovery.d.ts +1 -2
- package/dist/node/contribution-discovery.js +3 -3
- package/dist/node/session-store-jsonl.js +10 -7
- package/dist/node/settings.d.ts +1 -1
- package/dist/node/settings.js +1 -1
- package/dist/node/system-project-prompts.js +2 -4
- package/dist/node/trust.js +1 -1
- package/dist/persistence-lifecycle.js +1 -3
- package/dist/provider-events.js +3 -1
- package/dist/provider-request-policy.js +3 -4
- package/dist/providers/media.d.ts +1 -1
- package/dist/providers/openai-compatible.d.ts +42 -1
- package/dist/providers/openai-compatible.js +110 -49
- package/dist/providers/openai-primitives.js +7 -7
- package/dist/providers/transport.d.ts +6 -0
- package/dist/providers/transport.js +21 -0
- package/dist/providers.d.ts +2 -0
- package/dist/providers.js +3 -0
- package/dist/redaction.d.ts +1 -0
- package/dist/redaction.js +26 -9
- package/dist/resources.d.ts +2 -2
- package/dist/resources.js +2 -2
- package/dist/retry.d.ts +5 -0
- package/dist/retry.js +8 -1
- package/dist/rpc.js +42 -9
- package/dist/run-ledger.d.ts +6 -0
- package/dist/run-ledger.js +16 -13
- package/dist/run-limits.js +49 -10
- package/dist/secure-agent.js +1 -1
- package/dist/security.js +7 -2
- package/dist/session-stores.d.ts +1 -1
- package/dist/session-stores.js +28 -24
- package/dist/structured-output.js +2 -2
- package/dist/system-prompts.js +7 -2
- package/dist/testing/compaction-conformance.js +5 -1
- package/dist/testing/extension-conformance.js +15 -3
- package/dist/testing/feedback.d.ts +1 -3
- package/dist/testing/feedback.js +1 -1
- package/dist/testing/persistence-schema.js +206 -37
- package/dist/testing/provider-conformance.js +3 -3
- package/dist/testing/run-ledger-conformance.js +1 -1
- package/dist/testing/session-store-conformance.js +1 -1
- package/dist/testing/tool-conformance.js +30 -5
- package/dist/thinking.js +4 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +24 -5
- package/docs/0.1.0-readiness.md +139 -0
- package/docs/agent-events.md +2 -1
- package/docs/agent-session-runtime.md +2 -2
- package/docs/cli-rpc.md +1 -5
- package/docs/coding-agent-tools.md +2 -0
- package/docs/compaction-and-retry.md +3 -1
- package/docs/contribution-registries.md +1 -0
- package/docs/credentials-and-redaction.md +1 -1
- package/docs/extensions.md +1 -1
- package/docs/guardrails.md +13 -2
- package/docs/index.md +4 -2
- package/docs/input-and-prompt-assembly.md +3 -3
- package/docs/middleware-hooks.md +2 -2
- package/docs/migration.md +40 -0
- package/docs/performance.md +33 -0
- package/docs/providers/openai-compatible.md +28 -1
- package/docs/public-contracts.md +2 -2
- package/docs/release-and-install.md +127 -17
- package/docs/session-stores.md +1 -1
- package/package.json +14 -6
- package/docs/review-coverage-2026-07-14.md +0 -260
- package/docs/review-coverage-2026-07-15.md +0 -193
- package/docs/review-coverage-2026-07-17-provider-validation.md +0 -192
- package/docs/review-coverage-2026-07-19-phase-3.md +0 -174
- package/docs/review-coverage-2026-07-20-phase-4.md +0 -175
- package/docs/review-coverage-2026-07-21-phase-5.md +0 -172
- package/docs/review-coverage-2026-07-22-phase-6.md +0 -209
- package/docs/review-coverage-2026-07-22-phase-7.md +0 -173
- package/docs/review-coverage-2026-07-23-phase-8.md +0 -245
- package/docs/review-coverage-2026-07-25-phase-9.md +0 -256
- package/docs/review-coverage-2026-07-26-phase-10.md +0 -132
package/dist/contributions.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type ProviderRegistry } from "./providers.js";
|
|
|
4
4
|
import { type DuplicateRegistrationOptions } from "./registry-options.js";
|
|
5
5
|
export interface ContributionRegistry<T> {
|
|
6
6
|
register(key: string, contribution: T): void;
|
|
7
|
+
/** Remove a contribution; returns false when the key was not registered. */
|
|
8
|
+
unregister(key: string): boolean;
|
|
7
9
|
get(key: string): T | undefined;
|
|
8
10
|
resolve(key: string): T;
|
|
9
11
|
list(): readonly T[];
|
package/dist/contributions.js
CHANGED
|
@@ -9,6 +9,9 @@ export function createContributionRegistry(options = {}) {
|
|
|
9
9
|
assertCanRegister(byKey, key, label, key, options.duplicate);
|
|
10
10
|
byKey.set(key, contribution);
|
|
11
11
|
},
|
|
12
|
+
unregister(key) {
|
|
13
|
+
return byKey.delete(key);
|
|
14
|
+
},
|
|
12
15
|
get(key) {
|
|
13
16
|
return byKey.get(key);
|
|
14
17
|
},
|
package/dist/conversations.js
CHANGED
|
@@ -56,7 +56,8 @@ export function conversationThreadFromRecord(record) {
|
|
|
56
56
|
const branches = [];
|
|
57
57
|
if (Array.isArray(value.branches)) {
|
|
58
58
|
for (const item of value.branches) {
|
|
59
|
-
if (item &&
|
|
59
|
+
if (item &&
|
|
60
|
+
typeof item === "object" &&
|
|
60
61
|
typeof item.leafId === "string" &&
|
|
61
62
|
typeof item.createdAt === "string") {
|
|
62
63
|
branches.push({
|
package/dist/credentials.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Credential,
|
|
1
|
+
import type { Credential, CredentialRequest, CredentialResolver, CredentialResolverSource, OAuthCredentialStore, OAuthCredentials, OAuthProvider } from "./contracts.js";
|
|
2
2
|
export type CredentialValueSource = string | (() => string | undefined | Promise<string | undefined>) | CredentialResolver;
|
|
3
3
|
export interface CredentialRecord {
|
|
4
4
|
readonly name: string;
|
|
@@ -10,7 +10,13 @@ export interface MemoryCredentialStore extends CredentialResolver {
|
|
|
10
10
|
delete(request: Pick<CredentialRequest, "name" | "provider">): boolean;
|
|
11
11
|
clear(): void;
|
|
12
12
|
}
|
|
13
|
-
export
|
|
13
|
+
export interface MemoryCredentialStoreOptions {
|
|
14
|
+
/** When true (default, backward compatible), a provider-scoped request falls back to a
|
|
15
|
+
* providerless record of the same name — that record is then served to EVERY provider.
|
|
16
|
+
* Set false for exact-match-only resolution (strict provider scoping). */
|
|
17
|
+
readonly allowProviderFallback?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function createMemoryCredentialStore(initial?: readonly CredentialRecord[], options?: MemoryCredentialStoreOptions): MemoryCredentialStore;
|
|
14
20
|
export declare function createChainedCredentialResolver(resolvers: readonly CredentialResolver[]): CredentialResolver;
|
|
15
21
|
export declare function createExplicitCredentialResolver(sources: readonly CredentialResolverSource[]): CredentialResolver;
|
|
16
22
|
export declare function createEnvCredentialResolver(env: Readonly<Record<string, string | undefined>>, map: Readonly<Record<string, string>>): CredentialResolver;
|
package/dist/credentials.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export function createMemoryCredentialStore(initial = []) {
|
|
1
|
+
export function createMemoryCredentialStore(initial = [], options = {}) {
|
|
2
2
|
const records = new Map();
|
|
3
|
+
const allowProviderFallback = options.allowProviderFallback ?? true;
|
|
3
4
|
const key = (name, provider) => `${provider ?? ""}\u0000${name}`;
|
|
4
5
|
const store = {
|
|
5
6
|
set(record) {
|
|
@@ -12,7 +13,10 @@ export function createMemoryCredentialStore(initial = []) {
|
|
|
12
13
|
records.clear();
|
|
13
14
|
},
|
|
14
15
|
resolve(request) {
|
|
15
|
-
|
|
16
|
+
const exact = records.get(key(request.name, request.provider));
|
|
17
|
+
if (exact !== undefined || !allowProviderFallback || request.provider === undefined)
|
|
18
|
+
return exact;
|
|
19
|
+
return records.get(key(request.name));
|
|
16
20
|
},
|
|
17
21
|
};
|
|
18
22
|
for (const record of initial)
|
|
@@ -37,7 +41,9 @@ export function createExplicitCredentialResolver(sources) {
|
|
|
37
41
|
export function createEnvCredentialResolver(env, map) {
|
|
38
42
|
return {
|
|
39
43
|
resolve(request) {
|
|
40
|
-
const envName = map[credentialMapKey(request.name, request.provider)] ??
|
|
44
|
+
const envName = map[credentialMapKey(request.name, request.provider)] ??
|
|
45
|
+
(request.provider ? map[request.provider] : undefined) ??
|
|
46
|
+
map[request.name];
|
|
41
47
|
const value = envName ? env[envName] : undefined;
|
|
42
48
|
return value ? { type: "api_key", value, metadata: { source: "env", envName } } : undefined;
|
|
43
49
|
},
|
|
@@ -13,10 +13,21 @@ export function createEventMultiplexer(options = {}) {
|
|
|
13
13
|
isClosed = true;
|
|
14
14
|
else
|
|
15
15
|
options.signal?.addEventListener("abort", abort, { once: true });
|
|
16
|
+
// With compare set, publish always enqueues and the parked consumer is woken with
|
|
17
|
+
// this token instead of a value, so every event drains through the sorted queue —
|
|
18
|
+
// delivery order follows the comparator even when the consumer is caught up.
|
|
19
|
+
const WAKE = Symbol("wake");
|
|
20
|
+
const wakeWaiter = () => {
|
|
21
|
+
if (!waiter)
|
|
22
|
+
return;
|
|
23
|
+
const resolve = waiter;
|
|
24
|
+
waiter = undefined;
|
|
25
|
+
resolve({ value: WAKE, done: false });
|
|
26
|
+
};
|
|
16
27
|
function publish(event) {
|
|
17
28
|
if (isClosed)
|
|
18
29
|
return;
|
|
19
|
-
if (waiter) {
|
|
30
|
+
if (!options.compare && waiter) {
|
|
20
31
|
const resolve = waiter;
|
|
21
32
|
waiter = undefined;
|
|
22
33
|
resolve({ value: event, done: false });
|
|
@@ -24,12 +35,11 @@ export function createEventMultiplexer(options = {}) {
|
|
|
24
35
|
}
|
|
25
36
|
if (queue.length < maxQueuedEvents) {
|
|
26
37
|
queue.push(event);
|
|
38
|
+
wakeWaiter();
|
|
27
39
|
return;
|
|
28
40
|
}
|
|
29
41
|
droppedEvents += 1;
|
|
30
|
-
const notice = !overflowNotified && options.overflowEvent
|
|
31
|
-
? options.overflowEvent({ droppedEvents, maxQueuedEvents, policy: overflow })
|
|
32
|
-
: undefined;
|
|
42
|
+
const notice = !overflowNotified && options.overflowEvent ? options.overflowEvent({ droppedEvents, maxQueuedEvents, policy: overflow }) : undefined;
|
|
33
43
|
overflowNotified = true;
|
|
34
44
|
if (overflow === "close") {
|
|
35
45
|
queue.length = 0;
|
|
@@ -43,6 +53,7 @@ export function createEventMultiplexer(options = {}) {
|
|
|
43
53
|
if (overflow === "drop_newest") {
|
|
44
54
|
if (notice !== undefined)
|
|
45
55
|
queue[queue.length - 1] = notice;
|
|
56
|
+
wakeWaiter();
|
|
46
57
|
return;
|
|
47
58
|
}
|
|
48
59
|
queue.shift();
|
|
@@ -52,6 +63,7 @@ export function createEventMultiplexer(options = {}) {
|
|
|
52
63
|
queue.shift();
|
|
53
64
|
}
|
|
54
65
|
queue.push(event);
|
|
66
|
+
wakeWaiter();
|
|
55
67
|
}
|
|
56
68
|
function observe(source, map) {
|
|
57
69
|
if (isClosed)
|
|
@@ -117,6 +129,8 @@ export function createEventMultiplexer(options = {}) {
|
|
|
117
129
|
});
|
|
118
130
|
if (next.done)
|
|
119
131
|
return;
|
|
132
|
+
if (next.value === WAKE)
|
|
133
|
+
continue;
|
|
120
134
|
yield next.value;
|
|
121
135
|
}
|
|
122
136
|
}
|
package/dist/extensions.d.ts
CHANGED
|
@@ -26,11 +26,17 @@ export interface ExtensionEventBus {
|
|
|
26
26
|
on(type: ExtensionLifecycleEventName | string, handler: ExtensionEventHandler): () => void;
|
|
27
27
|
emit(event: ExtensionEvent): Promise<void>;
|
|
28
28
|
}
|
|
29
|
+
export interface LoadedExtension {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/** Remove this extension's registry contributions and middleware/event subscriptions.
|
|
32
|
+
* Best-effort and idempotent; side effects outside the registries are NOT unwound. */
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
|
29
35
|
export interface ExtensionKernel {
|
|
30
36
|
readonly registries: ContributionRegistries;
|
|
31
37
|
readonly middleware: MiddlewareRegistry;
|
|
32
38
|
readonly events: ExtensionEventBus;
|
|
33
|
-
load(extensions: readonly Extension[]): Promise<
|
|
39
|
+
load(extensions: readonly Extension[]): Promise<LoadedExtension[]>;
|
|
34
40
|
}
|
|
35
41
|
export declare function createExtensionEventBus(options?: Pick<ExtensionKernelOptions, "errorPolicy" | "secrets">): ExtensionEventBus;
|
|
36
42
|
export declare function createExtensionKernel(options?: ExtensionKernelOptions): ExtensionKernel;
|
package/dist/extensions.js
CHANGED
|
@@ -45,90 +45,148 @@ export function createExtensionKernel(options = {}) {
|
|
|
45
45
|
const middleware = options.middleware ?? createMiddlewareRegistry({ ...options, onError: events.emit });
|
|
46
46
|
const errorPolicy = options.errorPolicy ?? "event";
|
|
47
47
|
const secrets = options.secrets ?? [];
|
|
48
|
-
|
|
48
|
+
// Per-extension tracked API: every registration records an undo so a dispose handle
|
|
49
|
+
// (or a failed setup) can unwind exactly what that extension added.
|
|
50
|
+
const createApi = (track) => ({
|
|
49
51
|
registries,
|
|
50
52
|
middleware,
|
|
51
|
-
on
|
|
53
|
+
on(type, handler) {
|
|
54
|
+
const off = events.on(type, handler);
|
|
55
|
+
track?.(off);
|
|
56
|
+
return off;
|
|
57
|
+
},
|
|
52
58
|
emit: events.emit,
|
|
53
|
-
use
|
|
59
|
+
use(hook, mw) {
|
|
60
|
+
const off = middleware.use(hook, mw);
|
|
61
|
+
track?.(off);
|
|
62
|
+
return off;
|
|
63
|
+
},
|
|
54
64
|
registerProvider(provider) {
|
|
55
65
|
registries.providers.register(provider);
|
|
66
|
+
track?.(() => registries.providers.unregister(provider.id));
|
|
56
67
|
},
|
|
57
68
|
registerModel(model) {
|
|
58
69
|
registries.models.register(model);
|
|
70
|
+
track?.(() => registries.models.unregister(model.provider, model.model));
|
|
59
71
|
},
|
|
60
72
|
registerTool(tool) {
|
|
61
73
|
registries.tools.register(tool.name, tool);
|
|
74
|
+
track?.(() => registries.tools.unregister(tool.name));
|
|
62
75
|
},
|
|
63
76
|
registerContextProvider(provider) {
|
|
64
77
|
registries.contextProviders.register(provider.name, provider);
|
|
78
|
+
track?.(() => registries.contextProviders.unregister(provider.name));
|
|
65
79
|
},
|
|
66
80
|
registerSkill(skill) {
|
|
67
81
|
registries.skills.register(skill.name, skill);
|
|
82
|
+
track?.(() => registries.skills.unregister(skill.name));
|
|
68
83
|
},
|
|
69
84
|
registerCommand(command) {
|
|
70
85
|
registries.commands.register(command.name, command);
|
|
86
|
+
track?.(() => registries.commands.unregister(command.name));
|
|
71
87
|
},
|
|
72
88
|
registerAgent(agent) {
|
|
73
89
|
registries.agents.register(agent.name, agent);
|
|
90
|
+
track?.(() => registries.agents.unregister(agent.name));
|
|
74
91
|
},
|
|
75
92
|
registerInputBuilder(builder) {
|
|
76
93
|
registries.inputBuilders.register(builder.name, builder);
|
|
94
|
+
track?.(() => registries.inputBuilders.unregister(builder.name));
|
|
77
95
|
},
|
|
78
96
|
registerPromptBuilder(builder) {
|
|
79
97
|
registries.promptBuilders.register(builder.name, builder);
|
|
98
|
+
track?.(() => registries.promptBuilders.unregister(builder.name));
|
|
80
99
|
},
|
|
81
100
|
registerCompactionStrategy(strategy) {
|
|
82
101
|
registries.compactionStrategies.register(strategy.name, strategy);
|
|
102
|
+
track?.(() => registries.compactionStrategies.unregister(strategy.name));
|
|
83
103
|
},
|
|
84
104
|
registerRetryPolicy(policy) {
|
|
85
105
|
registries.retryPolicies.register(policy.name, policy);
|
|
106
|
+
track?.(() => registries.retryPolicies.unregister(policy.name));
|
|
86
107
|
},
|
|
87
108
|
registerStoreFactory(factory) {
|
|
88
109
|
registries.storeFactories.register(factory.name, factory);
|
|
110
|
+
track?.(() => registries.storeFactories.unregister(factory.name));
|
|
89
111
|
},
|
|
90
112
|
registerResourceLoader(key, loader) {
|
|
91
113
|
registries.resourceLoaders.register(key, loader);
|
|
114
|
+
track?.(() => registries.resourceLoaders.unregister(key));
|
|
92
115
|
},
|
|
93
116
|
registerSettingsProvider(key, provider) {
|
|
94
117
|
registries.settingsProviders.register(key, provider);
|
|
118
|
+
track?.(() => registries.settingsProviders.unregister(key));
|
|
95
119
|
},
|
|
96
120
|
registerCredentialResolver(key, resolver) {
|
|
97
121
|
registries.credentialResolvers.register(key, resolver);
|
|
122
|
+
track?.(() => registries.credentialResolvers.unregister(key));
|
|
98
123
|
},
|
|
99
124
|
registerProviderPackage(providerPackage) {
|
|
100
125
|
registries.providerPackages.register(providerPackage.name, providerPackage);
|
|
126
|
+
track?.(() => registries.providerPackages.unregister(providerPackage.name));
|
|
101
127
|
},
|
|
102
128
|
registerAuthMethod(method) {
|
|
103
|
-
|
|
129
|
+
const key = authMethodKey(method);
|
|
130
|
+
registries.authMethods.register(key, method);
|
|
131
|
+
track?.(() => registries.authMethods.unregister(key));
|
|
104
132
|
},
|
|
105
133
|
registerProviderRequestPolicy(policy) {
|
|
106
134
|
registries.providerRequestPolicies.register(policy.name, policy);
|
|
135
|
+
track?.(() => registries.providerRequestPolicies.unregister(policy.name));
|
|
107
136
|
},
|
|
108
137
|
registerSystemPromptContribution(contribution) {
|
|
109
|
-
|
|
138
|
+
const key = systemPromptContributionKey(contribution);
|
|
139
|
+
registries.systemPromptContributions.register(key, contribution);
|
|
140
|
+
track?.(() => registries.systemPromptContributions.unregister(key));
|
|
110
141
|
},
|
|
111
142
|
registerInstructionInjector(injector) {
|
|
112
143
|
registries.instructionInjectors.register(injector.name, injector);
|
|
144
|
+
track?.(() => registries.instructionInjectors.unregister(injector.name));
|
|
113
145
|
},
|
|
146
|
+
});
|
|
147
|
+
const unwind = (undo) => {
|
|
148
|
+
for (const fn of undo.reverse()) {
|
|
149
|
+
try {
|
|
150
|
+
fn();
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// best-effort: one stuck undo must not block the rest
|
|
154
|
+
}
|
|
155
|
+
}
|
|
114
156
|
};
|
|
115
157
|
return {
|
|
116
158
|
registries,
|
|
117
159
|
middleware,
|
|
118
160
|
events,
|
|
119
161
|
async load(extensions) {
|
|
162
|
+
const loaded = [];
|
|
120
163
|
for (const extension of extensions) {
|
|
164
|
+
const undo = [];
|
|
121
165
|
try {
|
|
122
166
|
await assertPermission(options.permission, { kind: "extension", action: "setup", target: extension.name });
|
|
123
167
|
await assertExtensionLoadPolicy(options.loadPolicy, extension);
|
|
124
|
-
await extension.setup(
|
|
168
|
+
await extension.setup(createApi((fn) => undo.push(fn)));
|
|
125
169
|
}
|
|
126
170
|
catch (error) {
|
|
171
|
+
// A failed setup must not leave partial contributions behind.
|
|
172
|
+
unwind(undo);
|
|
127
173
|
if (errorPolicy === "throw")
|
|
128
174
|
throw error;
|
|
129
175
|
await events.emit(extensionError(error, extension.name, secrets));
|
|
176
|
+
continue;
|
|
130
177
|
}
|
|
178
|
+
let disposed = false;
|
|
179
|
+
loaded.push({
|
|
180
|
+
name: extension.name,
|
|
181
|
+
dispose() {
|
|
182
|
+
if (disposed)
|
|
183
|
+
return;
|
|
184
|
+
disposed = true;
|
|
185
|
+
unwind(undo);
|
|
186
|
+
},
|
|
187
|
+
});
|
|
131
188
|
}
|
|
189
|
+
return loaded;
|
|
132
190
|
},
|
|
133
191
|
};
|
|
134
192
|
}
|
package/dist/feedback.js
CHANGED
|
@@ -48,10 +48,14 @@ export async function prepareRunFeedback(input, options) {
|
|
|
48
48
|
const tags = normalizeList(input.tags, maxTags, MAX_FEEDBACK_TAG_LENGTH, "tag");
|
|
49
49
|
const scorerIds = normalizeList(input.scorerIds, maxLinks, MAX_FEEDBACK_ID_LENGTH, "scorer id", true);
|
|
50
50
|
const evaluationIds = normalizeList(input.evaluationIds, maxLinks, MAX_FEEDBACK_ID_LENGTH, "evaluation id", true);
|
|
51
|
-
if (input.rating === undefined &&
|
|
51
|
+
if (input.rating === undefined &&
|
|
52
|
+
input.comment === undefined &&
|
|
53
|
+
tags.length === 0 &&
|
|
54
|
+
scorerIds.length === 0 &&
|
|
55
|
+
evaluationIds.length === 0) {
|
|
52
56
|
throw new RunFeedbackError("feedback requires rating, comment, tag, scorer, or evaluation", "ERR_PRISM_RUN_FEEDBACK_EMPTY");
|
|
53
57
|
}
|
|
54
|
-
const redact = (value) => options.redactor ? options.redactor.redact(value) : value;
|
|
58
|
+
const redact = (value) => (options.redactor ? options.redactor.redact(value) : value);
|
|
55
59
|
const comment = input.comment === undefined ? undefined : redact(input.comment);
|
|
56
60
|
const safeTags = Object.freeze(normalizeList(redact(tags), maxTags, MAX_FEEDBACK_TAG_LENGTH, "tag"));
|
|
57
61
|
const metadata = input.metadata === undefined ? undefined : redact(input.metadata);
|
|
@@ -121,18 +125,16 @@ export function runFeedbackPageLimit(limit, maximum = HARD_FEEDBACK_PAGE_SIZE) {
|
|
|
121
125
|
return pageLimit(limit, maximum);
|
|
122
126
|
}
|
|
123
127
|
function requireOwnership(input) {
|
|
124
|
-
if (!input.tenantId?.trim()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
if (!input.tenantId?.trim() ||
|
|
129
|
+
(input.accountId !== undefined && !input.accountId.trim()) ||
|
|
130
|
+
(input.userId !== undefined && !input.userId.trim()) ||
|
|
131
|
+
(!input.accountId && !input.userId)) {
|
|
128
132
|
throw new RunFeedbackError("tenantId and non-empty accountId or userId are required", "ERR_PRISM_RUN_FEEDBACK_OWNERSHIP");
|
|
129
133
|
}
|
|
130
134
|
return { tenantId: input.tenantId, accountId: input.accountId, userId: input.userId };
|
|
131
135
|
}
|
|
132
136
|
function sameOwnership(expected, actual) {
|
|
133
|
-
return expected.tenantId === actual.tenantId
|
|
134
|
-
&& expected.accountId === actual.accountId
|
|
135
|
-
&& expected.userId === actual.userId;
|
|
137
|
+
return expected.tenantId === actual.tenantId && expected.accountId === actual.accountId && expected.userId === actual.userId;
|
|
136
138
|
}
|
|
137
139
|
function requireId(value, label) {
|
|
138
140
|
if (!value || value.length > MAX_FEEDBACK_ID_LENGTH || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value)) {
|
|
@@ -214,7 +216,7 @@ function freezeRecord(record) {
|
|
|
214
216
|
});
|
|
215
217
|
}
|
|
216
218
|
function cloneFrozenJsonObject(value) {
|
|
217
|
-
const cloned =
|
|
219
|
+
const cloned = structuredClone(value);
|
|
218
220
|
if (!cloned || typeof cloned !== "object" || Array.isArray(cloned))
|
|
219
221
|
throw new RunFeedbackError("metadata must be a JSON object");
|
|
220
222
|
return deepFreeze(cloned);
|
package/dist/guardrails.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentEvent, GuardrailContext, GuardrailRecord,
|
|
1
|
+
import type { AgentEvent, GuardrailContext, GuardrailRecord, GuardrailStage, Guardrails, GuardrailValue } from "./contracts.js";
|
|
2
2
|
import type { SecretRedactor } from "./redaction.js";
|
|
3
3
|
export declare const MAX_GUARDRAIL_CONCURRENCY = 16;
|
|
4
4
|
export declare class GuardrailError extends Error {
|
package/dist/guardrails.js
CHANGED
|
@@ -5,11 +5,11 @@ export class GuardrailError extends Error {
|
|
|
5
5
|
code;
|
|
6
6
|
record;
|
|
7
7
|
constructor(record) {
|
|
8
|
-
super(record.action === "interrupt"
|
|
8
|
+
super(record.action === "interrupt"
|
|
9
|
+
? `Guardrail interruption is unavailable at stage "${record.stage}"; interrupt suspends only at the input stage of durable runs`
|
|
10
|
+
: "Guardrail blocked run");
|
|
9
11
|
this.name = "GuardrailError";
|
|
10
|
-
this.code = record.action === "interrupt"
|
|
11
|
-
? "ERR_PRISM_GUARDRAIL_INTERRUPT_UNAVAILABLE"
|
|
12
|
-
: "ERR_PRISM_GUARDRAIL_BLOCKED";
|
|
12
|
+
this.code = record.action === "interrupt" ? "ERR_PRISM_GUARDRAIL_INTERRUPT_UNAVAILABLE" : "ERR_PRISM_GUARDRAIL_BLOCKED";
|
|
13
13
|
this.record = record;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -20,9 +20,7 @@ export async function runGuardrails(options) {
|
|
|
20
20
|
return { records: [] };
|
|
21
21
|
const maxConcurrency = resolveConcurrency(options.guardrails?.maxConcurrency);
|
|
22
22
|
const controller = new AbortController();
|
|
23
|
-
const signal = options.context.signal
|
|
24
|
-
? AbortSignal.any([options.context.signal, controller.signal])
|
|
25
|
-
: controller.signal;
|
|
23
|
+
const signal = options.context.signal ? AbortSignal.any([options.context.signal, controller.signal]) : controller.signal;
|
|
26
24
|
const records = new Array(guards.length);
|
|
27
25
|
let next = 0;
|
|
28
26
|
let stopped = false;
|
|
@@ -66,14 +64,23 @@ function stageGuards(guardrails, stage) {
|
|
|
66
64
|
if (!guardrails)
|
|
67
65
|
return [];
|
|
68
66
|
switch (stage) {
|
|
69
|
-
case "input":
|
|
70
|
-
|
|
71
|
-
case "
|
|
72
|
-
|
|
67
|
+
case "input":
|
|
68
|
+
return (guardrails.input ?? []);
|
|
69
|
+
case "output":
|
|
70
|
+
return (guardrails.output ?? []);
|
|
71
|
+
case "tool_input":
|
|
72
|
+
return (guardrails.toolInput ?? []);
|
|
73
|
+
case "tool_output":
|
|
74
|
+
return (guardrails.toolOutput ?? []);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
async function evaluate(guardrail, options, signal) {
|
|
76
|
-
if (!guardrail ||
|
|
78
|
+
if (!guardrail ||
|
|
79
|
+
typeof guardrail.name !== "string" ||
|
|
80
|
+
!guardrail.name ||
|
|
81
|
+
guardrail.name.length > 128 ||
|
|
82
|
+
guardrail.stage !== options.stage ||
|
|
83
|
+
typeof guardrail.evaluate !== "function") {
|
|
77
84
|
return record(guardrail?.name ?? "invalid", options.stage, "tripwire", "guardrail_invalid", undefined, options.redactor);
|
|
78
85
|
}
|
|
79
86
|
try {
|
|
@@ -83,8 +90,12 @@ async function evaluate(guardrail, options, signal) {
|
|
|
83
90
|
}
|
|
84
91
|
return record(guardrail.name, options.stage, decision.action, decision.reason, decision.metadata, options.redactor);
|
|
85
92
|
}
|
|
86
|
-
catch {
|
|
87
|
-
|
|
93
|
+
catch (error) {
|
|
94
|
+
// Keep the cause diagnosable without leaking internals: message only, bounded and
|
|
95
|
+
// passed through the same redact+bound metadata path as guardrail-provided metadata.
|
|
96
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
97
|
+
const redacted = options.redactor?.redact(message) ?? message;
|
|
98
|
+
return record(guardrail.name, options.stage, "tripwire", "guardrail_failed", { error: boundText(redacted, MAX_REASON_BYTES) }, options.redactor);
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
function resolveConcurrency(value) {
|
|
@@ -115,9 +126,7 @@ function boundedMetadata(value, redactor) {
|
|
|
115
126
|
if (!json || byteLength(json) > MAX_METADATA_BYTES)
|
|
116
127
|
return { truncated: true };
|
|
117
128
|
const parsed = JSON.parse(json);
|
|
118
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
119
|
-
? parsed
|
|
120
|
-
: undefined;
|
|
129
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
|
|
121
130
|
}
|
|
122
131
|
catch {
|
|
123
132
|
return { invalid: true };
|
package/dist/identity.js
CHANGED
|
@@ -104,9 +104,17 @@ export function narrowIdentity(parent, options) {
|
|
|
104
104
|
scopes: Object.freeze([...options.scopes]),
|
|
105
105
|
credentialRefs: Object.freeze([...(options.credentialRefs ?? parent.credentialRefs ?? [])]),
|
|
106
106
|
issuedAt: parent.issuedAt,
|
|
107
|
-
...(options.expiresAt !== undefined
|
|
107
|
+
...(options.expiresAt !== undefined
|
|
108
|
+
? { expiresAt: options.expiresAt }
|
|
109
|
+
: parent.expiresAt !== undefined
|
|
110
|
+
? { expiresAt: parent.expiresAt }
|
|
111
|
+
: {}),
|
|
108
112
|
...(parent.revokedAt !== undefined ? { revokedAt: parent.revokedAt } : {}),
|
|
109
|
-
...(options.metadata !== undefined
|
|
113
|
+
...(options.metadata !== undefined
|
|
114
|
+
? { metadata: options.metadata }
|
|
115
|
+
: parent.metadata !== undefined
|
|
116
|
+
? { metadata: parent.metadata }
|
|
117
|
+
: {}),
|
|
110
118
|
verified: true,
|
|
111
119
|
};
|
|
112
120
|
assertIdentityActive(child, { limits: options.limits });
|