@arnilo/prism 0.0.3 → 0.0.5
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 +40 -0
- package/README.md +62 -26
- package/dist/agent-loops.d.ts +8 -1
- package/dist/agent-loops.js +57 -11
- package/dist/agents.js +212 -32
- package/dist/checkpoints.d.ts +11 -0
- package/dist/checkpoints.js +144 -0
- package/dist/cli-init.d.ts +41 -0
- package/dist/cli-init.js +390 -0
- package/dist/cli-runner.d.ts +7 -1
- package/dist/cli-runner.js +13 -1
- package/dist/compaction.js +9 -1
- package/dist/content.d.ts +121 -0
- package/dist/content.js +538 -0
- package/dist/contracts.d.ts +236 -11
- package/dist/contracts.js +8 -0
- package/dist/event-multiplexer.d.ts +23 -0
- package/dist/event-multiplexer.js +136 -0
- package/dist/execution-policy.d.ts +28 -0
- package/dist/execution-policy.js +24 -0
- package/dist/feedback.d.ts +48 -0
- package/dist/feedback.js +230 -0
- package/dist/index.d.ts +20 -6
- package/dist/index.js +13 -5
- package/dist/input.js +11 -1
- package/dist/leases.d.ts +8 -0
- package/dist/leases.js +111 -0
- package/dist/node/agent-definitions.js +3 -5
- package/dist/node/config.d.ts +1 -0
- package/dist/node/config.js +5 -3
- package/dist/node/contribution-discovery.js +5 -8
- package/dist/node/session-store-jsonl.js +8 -5
- package/dist/node/settings.js +2 -2
- package/dist/node/trust.js +2 -4
- package/dist/observability.d.ts +3 -0
- package/dist/observability.js +18 -0
- package/dist/providers/media.d.ts +44 -0
- package/dist/providers/media.js +126 -0
- package/dist/providers/openai-compatible.js +18 -119
- package/dist/providers/openai-primitives.d.ts +9 -0
- package/dist/providers/openai-primitives.js +129 -0
- package/dist/providers/transport.d.ts +40 -0
- package/dist/providers/transport.js +221 -0
- package/dist/redaction.js +40 -13
- package/dist/resources.d.ts +5 -0
- package/dist/resources.js +4 -0
- package/dist/structured-output.d.ts +11 -0
- package/dist/structured-output.js +59 -0
- package/dist/testing/feedback.d.ts +6 -0
- package/dist/testing/feedback.js +37 -0
- package/dist/testing/persistence-schema.d.ts +102 -0
- package/dist/testing/persistence-schema.js +487 -0
- package/dist/testing/provider-conformance.js +10 -1
- package/dist/testing/run-ledger-conformance.d.ts +33 -0
- package/dist/testing/run-ledger-conformance.js +178 -0
- package/dist/testing/session-store-conformance.d.ts +16 -0
- package/dist/testing/session-store-conformance.js +73 -0
- package/dist/tools.d.ts +17 -0
- package/dist/tools.js +29 -2
- package/docs/a2a.md +73 -0
- package/docs/agent-events.md +17 -10
- package/docs/agent-loops.md +11 -5
- package/docs/agent-session-runtime.md +15 -16
- package/docs/cli-rpc.md +36 -5
- package/docs/coding-agent-tools.md +43 -9
- package/docs/coding-security.md +88 -0
- package/docs/compaction-observational-memory.md +2 -0
- package/docs/context-and-skills.md +1 -0
- package/docs/credential-storage.md +177 -0
- package/docs/credentials-and-redaction.md +4 -3
- package/docs/database-persistence.md +52 -7
- package/docs/evaluations.md +122 -0
- package/docs/extensions.md +2 -2
- package/docs/host-security.md +33 -2
- package/docs/index.md +46 -18
- package/docs/input-and-prompt-assembly.md +6 -5
- package/docs/mcp-tools.md +184 -0
- package/docs/middleware-hooks.md +2 -0
- package/docs/migration.md +51 -28
- package/docs/model-registry.md +5 -3
- package/docs/multimodal-content.md +156 -0
- package/docs/observability.md +171 -0
- package/docs/performance.md +249 -1
- package/docs/persistence-credentials-multimodality-primitives.md +303 -0
- package/docs/postgres-persistence.md +143 -0
- package/docs/provider-conformance.md +18 -0
- package/docs/provider-layer.md +1 -1
- package/docs/provider-packages.md +2 -0
- package/docs/provider-primitives.md +281 -0
- package/docs/providers/ai-sdk.md +113 -0
- package/docs/providers/kimi.md +1 -0
- package/docs/providers/neuralwatt.md +1 -0
- package/docs/providers/openai-compatible.md +2 -1
- package/docs/providers/openai.md +8 -1
- package/docs/providers/opencode-go.md +1 -0
- package/docs/providers/openrouter.md +1 -0
- package/docs/providers/zai.md +1 -0
- package/docs/public-contracts.md +13 -5
- package/docs/rag.md +113 -0
- package/docs/release-and-install.md +237 -30
- package/docs/resource-loading.md +14 -4
- package/docs/review-coverage-2026-07-14.md +260 -0
- package/docs/review-coverage-2026-07-15.md +193 -0
- package/docs/run-ledger-conformance.md +96 -0
- package/docs/runs-and-usage.md +43 -4
- package/docs/server.md +139 -0
- package/docs/session-store-conformance.md +16 -0
- package/docs/session-stores-and-branching.md +1 -0
- package/docs/settings-auth-trust-security.md +6 -5
- package/docs/sqlite-persistence.md +123 -0
- package/docs/structured-output.md +9 -0
- package/docs/supervisors.md +71 -0
- package/docs/tool-conformance.md +1 -0
- package/docs/tool-execution-primitives.md +374 -0
- package/docs/tools.md +39 -1
- package/docs/workflow-orchestration-primitives.md +581 -0
- package/docs/workflow-tui-primitives.md +5 -0
- package/docs/workflows.md +293 -0
- package/docs/working-and-semantic-memory.md +169 -0
- package/package.json +43 -5
- package/templates/init/README.md.tmpl +28 -0
- package/templates/init/env.example.tmpl +1 -0
- package/templates/init/gitignore.tmpl +11 -0
- package/templates/init/optional/evals-example.ts.tmpl +17 -0
- package/templates/init/optional/workflows-example.ts.tmpl +27 -0
- package/templates/init/package.json.tmpl +22 -0
- package/templates/init/providers.json +76 -0
- package/templates/init/src/agent.ts.tmpl +10 -0
- package/templates/init/src/index.ts.tmpl +12 -0
- package/templates/init/src/tests/agent.test.ts.tmpl +24 -0
- package/templates/init/tsconfig.json.tmpl +15 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { AppendRunFeedbackInput, OwnershipScope, RunFeedbackRecord, RunFeedbackStore } from "./contracts.js";
|
|
2
|
+
import type { SecretRedactor } from "./redaction.js";
|
|
3
|
+
export declare const DEFAULT_MAX_FEEDBACK_COMMENT_BYTES = 4096;
|
|
4
|
+
export declare const HARD_MAX_FEEDBACK_COMMENT_BYTES = 16384;
|
|
5
|
+
export declare const DEFAULT_MAX_FEEDBACK_TAGS = 16;
|
|
6
|
+
export declare const HARD_MAX_FEEDBACK_TAGS = 64;
|
|
7
|
+
export declare const DEFAULT_MAX_FEEDBACK_LINKS = 16;
|
|
8
|
+
export declare const HARD_MAX_FEEDBACK_LINKS = 64;
|
|
9
|
+
export declare const DEFAULT_MAX_FEEDBACK_METADATA_BYTES = 16384;
|
|
10
|
+
export declare const HARD_MAX_FEEDBACK_METADATA_BYTES = 65536;
|
|
11
|
+
export declare const DEFAULT_FEEDBACK_PAGE_SIZE = 100;
|
|
12
|
+
export declare const HARD_FEEDBACK_PAGE_SIZE = 500;
|
|
13
|
+
export declare const MAX_FEEDBACK_TAG_LENGTH = 64;
|
|
14
|
+
export declare const MAX_FEEDBACK_ID_LENGTH = 128;
|
|
15
|
+
export declare class RunFeedbackError extends Error {
|
|
16
|
+
readonly code: string;
|
|
17
|
+
constructor(message: string, code?: string);
|
|
18
|
+
}
|
|
19
|
+
export interface RunFeedbackRun extends OwnershipScope {
|
|
20
|
+
readonly runId: string;
|
|
21
|
+
readonly sessionId: string;
|
|
22
|
+
readonly traceId?: string;
|
|
23
|
+
}
|
|
24
|
+
export type RunFeedbackRunResolver = (input: Readonly<{
|
|
25
|
+
runId: string;
|
|
26
|
+
ownership: OwnershipScope;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
}>) => RunFeedbackRun | false | undefined | Promise<RunFeedbackRun | false | undefined>;
|
|
29
|
+
export interface RunFeedbackLimits {
|
|
30
|
+
readonly maxCommentBytes?: number;
|
|
31
|
+
readonly maxTags?: number;
|
|
32
|
+
readonly maxLinks?: number;
|
|
33
|
+
readonly maxMetadataBytes?: number;
|
|
34
|
+
readonly maxPageSize?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface PrepareRunFeedbackOptions extends RunFeedbackLimits {
|
|
37
|
+
readonly resolveRun: RunFeedbackRunResolver;
|
|
38
|
+
readonly redactor?: SecretRedactor;
|
|
39
|
+
}
|
|
40
|
+
export interface MemoryRunFeedbackStoreOptions extends PrepareRunFeedbackOptions {
|
|
41
|
+
readonly initial?: readonly RunFeedbackRecord[];
|
|
42
|
+
}
|
|
43
|
+
/** Validate, ownership-check, redact, bound, and freeze one feedback record. */
|
|
44
|
+
export declare function prepareRunFeedback(input: AppendRunFeedbackInput, options: PrepareRunFeedbackOptions): Promise<RunFeedbackRecord>;
|
|
45
|
+
/** In-memory implementation with the same validation/ownership semantics as durable adapters. */
|
|
46
|
+
export declare function createMemoryRunFeedbackStore(options: MemoryRunFeedbackStoreOptions): RunFeedbackStore;
|
|
47
|
+
export declare function requireRunFeedbackOwnership(input: OwnershipScope): Required<Pick<OwnershipScope, "tenantId">> & OwnershipScope;
|
|
48
|
+
export declare function runFeedbackPageLimit(limit: number | undefined, maximum?: number): number;
|
package/dist/feedback.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
export const DEFAULT_MAX_FEEDBACK_COMMENT_BYTES = 4096;
|
|
2
|
+
export const HARD_MAX_FEEDBACK_COMMENT_BYTES = 16384;
|
|
3
|
+
export const DEFAULT_MAX_FEEDBACK_TAGS = 16;
|
|
4
|
+
export const HARD_MAX_FEEDBACK_TAGS = 64;
|
|
5
|
+
export const DEFAULT_MAX_FEEDBACK_LINKS = 16;
|
|
6
|
+
export const HARD_MAX_FEEDBACK_LINKS = 64;
|
|
7
|
+
export const DEFAULT_MAX_FEEDBACK_METADATA_BYTES = 16384;
|
|
8
|
+
export const HARD_MAX_FEEDBACK_METADATA_BYTES = 65536;
|
|
9
|
+
export const DEFAULT_FEEDBACK_PAGE_SIZE = 100;
|
|
10
|
+
export const HARD_FEEDBACK_PAGE_SIZE = 500;
|
|
11
|
+
export const MAX_FEEDBACK_TAG_LENGTH = 64;
|
|
12
|
+
export const MAX_FEEDBACK_ID_LENGTH = 128;
|
|
13
|
+
export class RunFeedbackError extends Error {
|
|
14
|
+
code;
|
|
15
|
+
constructor(message, code = "ERR_PRISM_RUN_FEEDBACK") {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = "RunFeedbackError";
|
|
18
|
+
this.code = code;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/** Validate, ownership-check, redact, bound, and freeze one feedback record. */
|
|
22
|
+
export async function prepareRunFeedback(input, options) {
|
|
23
|
+
input.signal?.throwIfAborted();
|
|
24
|
+
const ownership = requireOwnership(input);
|
|
25
|
+
const id = requireId(input.id, "feedback id");
|
|
26
|
+
const runId = requireId(input.runId, "runId");
|
|
27
|
+
const run = await options.resolveRun({ runId, ownership, signal: input.signal });
|
|
28
|
+
input.signal?.throwIfAborted();
|
|
29
|
+
if (!run || run.runId !== runId || !sameOwnership(ownership, run)) {
|
|
30
|
+
throw new RunFeedbackError("Run not found", "ERR_PRISM_RUN_FEEDBACK_RUN_NOT_FOUND");
|
|
31
|
+
}
|
|
32
|
+
if (input.sessionId !== undefined && input.sessionId !== run.sessionId) {
|
|
33
|
+
throw new RunFeedbackError("Run not found", "ERR_PRISM_RUN_FEEDBACK_RUN_NOT_FOUND");
|
|
34
|
+
}
|
|
35
|
+
if (input.traceId !== undefined && run.traceId !== undefined && input.traceId !== run.traceId) {
|
|
36
|
+
throw new RunFeedbackError("Run not found", "ERR_PRISM_RUN_FEEDBACK_RUN_NOT_FOUND");
|
|
37
|
+
}
|
|
38
|
+
if (input.comment !== undefined && !input.comment.trim()) {
|
|
39
|
+
throw new RunFeedbackError("comment must not be empty", "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
40
|
+
}
|
|
41
|
+
if (input.rating !== undefined && (!Number.isFinite(input.rating) || input.rating < -1 || input.rating > 1)) {
|
|
42
|
+
throw new RunFeedbackError("rating must be a finite number in [-1, 1]", "ERR_PRISM_RUN_FEEDBACK_BOUNDS");
|
|
43
|
+
}
|
|
44
|
+
const maxCommentBytes = boundedLimit(options.maxCommentBytes, DEFAULT_MAX_FEEDBACK_COMMENT_BYTES, HARD_MAX_FEEDBACK_COMMENT_BYTES, "maxCommentBytes");
|
|
45
|
+
const maxTags = boundedLimit(options.maxTags, DEFAULT_MAX_FEEDBACK_TAGS, HARD_MAX_FEEDBACK_TAGS, "maxTags");
|
|
46
|
+
const maxLinks = boundedLimit(options.maxLinks, DEFAULT_MAX_FEEDBACK_LINKS, HARD_MAX_FEEDBACK_LINKS, "maxLinks");
|
|
47
|
+
const maxMetadataBytes = boundedLimit(options.maxMetadataBytes, DEFAULT_MAX_FEEDBACK_METADATA_BYTES, HARD_MAX_FEEDBACK_METADATA_BYTES, "maxMetadataBytes");
|
|
48
|
+
const tags = normalizeList(input.tags, maxTags, MAX_FEEDBACK_TAG_LENGTH, "tag");
|
|
49
|
+
const scorerIds = normalizeList(input.scorerIds, maxLinks, MAX_FEEDBACK_ID_LENGTH, "scorer id", true);
|
|
50
|
+
const evaluationIds = normalizeList(input.evaluationIds, maxLinks, MAX_FEEDBACK_ID_LENGTH, "evaluation id", true);
|
|
51
|
+
if (input.rating === undefined && input.comment === undefined && tags.length === 0 && scorerIds.length === 0 && evaluationIds.length === 0) {
|
|
52
|
+
throw new RunFeedbackError("feedback requires rating, comment, tag, scorer, or evaluation", "ERR_PRISM_RUN_FEEDBACK_EMPTY");
|
|
53
|
+
}
|
|
54
|
+
const redact = (value) => options.redactor ? options.redactor.redact(value) : value;
|
|
55
|
+
const comment = input.comment === undefined ? undefined : redact(input.comment);
|
|
56
|
+
const safeTags = Object.freeze(normalizeList(redact(tags), maxTags, MAX_FEEDBACK_TAG_LENGTH, "tag"));
|
|
57
|
+
const metadata = input.metadata === undefined ? undefined : redact(input.metadata);
|
|
58
|
+
assertBytes(comment, maxCommentBytes, "comment");
|
|
59
|
+
assertBytes(metadata, maxMetadataBytes, "metadata");
|
|
60
|
+
const createdAt = input.createdAt ?? new Date().toISOString();
|
|
61
|
+
if (!Number.isFinite(Date.parse(createdAt)))
|
|
62
|
+
throw new RunFeedbackError("createdAt must be an ISO timestamp", "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
63
|
+
return Object.freeze({
|
|
64
|
+
id,
|
|
65
|
+
runId,
|
|
66
|
+
sessionId: run.sessionId,
|
|
67
|
+
traceId: input.traceId ?? run.traceId,
|
|
68
|
+
rating: input.rating,
|
|
69
|
+
comment,
|
|
70
|
+
tags: safeTags,
|
|
71
|
+
scorerIds: Object.freeze(scorerIds),
|
|
72
|
+
evaluationIds: Object.freeze(evaluationIds),
|
|
73
|
+
createdAt,
|
|
74
|
+
createdBy: input.createdBy === undefined ? undefined : requireId(input.createdBy, "createdBy"),
|
|
75
|
+
metadata: metadata === undefined ? undefined : cloneFrozenJsonObject(metadata),
|
|
76
|
+
...ownership,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** In-memory implementation with the same validation/ownership semantics as durable adapters. */
|
|
80
|
+
export function createMemoryRunFeedbackStore(options) {
|
|
81
|
+
const records = new Map();
|
|
82
|
+
for (const record of options.initial ?? [])
|
|
83
|
+
records.set(record.id, freezeRecord(record));
|
|
84
|
+
const maxPageSize = boundedLimit(options.maxPageSize, DEFAULT_FEEDBACK_PAGE_SIZE, HARD_FEEDBACK_PAGE_SIZE, "maxPageSize");
|
|
85
|
+
return {
|
|
86
|
+
async append(input) {
|
|
87
|
+
if (records.has(input.id))
|
|
88
|
+
throw new RunFeedbackError("Duplicate feedback id", "ERR_PRISM_RUN_FEEDBACK_DUPLICATE");
|
|
89
|
+
const record = await prepareRunFeedback(input, options);
|
|
90
|
+
records.set(record.id, record);
|
|
91
|
+
return record;
|
|
92
|
+
},
|
|
93
|
+
async query(query) {
|
|
94
|
+
query.signal?.throwIfAborted();
|
|
95
|
+
const ownership = requireOwnership(query);
|
|
96
|
+
const limit = pageLimit(query.limit, maxPageSize);
|
|
97
|
+
const order = query.order === "desc" ? -1 : 1;
|
|
98
|
+
const sorted = [...records.values()]
|
|
99
|
+
.filter((record) => sameOwnership(ownership, record) && matchesQuery(record, query))
|
|
100
|
+
.sort((a, b) => order * (a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id)));
|
|
101
|
+
const start = query.cursor ? sorted.findIndex((record) => record.id === query.cursor) + 1 : 0;
|
|
102
|
+
if (query.cursor && start === 0)
|
|
103
|
+
throw new RunFeedbackError("Unknown feedback cursor", "ERR_PRISM_RUN_FEEDBACK_CURSOR");
|
|
104
|
+
const items = sorted.slice(start, start + limit);
|
|
105
|
+
return { items, nextCursor: start + items.length < sorted.length ? items.at(-1)?.id : undefined, total: sorted.length };
|
|
106
|
+
},
|
|
107
|
+
async delete(input) {
|
|
108
|
+
input.signal?.throwIfAborted();
|
|
109
|
+
const ownership = requireOwnership(input);
|
|
110
|
+
const current = records.get(input.id);
|
|
111
|
+
if (!current || !sameOwnership(ownership, current))
|
|
112
|
+
return false;
|
|
113
|
+
return records.delete(input.id);
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function requireRunFeedbackOwnership(input) {
|
|
118
|
+
return requireOwnership(input);
|
|
119
|
+
}
|
|
120
|
+
export function runFeedbackPageLimit(limit, maximum = HARD_FEEDBACK_PAGE_SIZE) {
|
|
121
|
+
return pageLimit(limit, maximum);
|
|
122
|
+
}
|
|
123
|
+
function requireOwnership(input) {
|
|
124
|
+
if (!input.tenantId?.trim()
|
|
125
|
+
|| (input.accountId !== undefined && !input.accountId.trim())
|
|
126
|
+
|| (input.userId !== undefined && !input.userId.trim())
|
|
127
|
+
|| (!input.accountId && !input.userId)) {
|
|
128
|
+
throw new RunFeedbackError("tenantId and non-empty accountId or userId are required", "ERR_PRISM_RUN_FEEDBACK_OWNERSHIP");
|
|
129
|
+
}
|
|
130
|
+
return { tenantId: input.tenantId, accountId: input.accountId, userId: input.userId };
|
|
131
|
+
}
|
|
132
|
+
function sameOwnership(expected, actual) {
|
|
133
|
+
return expected.tenantId === actual.tenantId
|
|
134
|
+
&& expected.accountId === actual.accountId
|
|
135
|
+
&& expected.userId === actual.userId;
|
|
136
|
+
}
|
|
137
|
+
function requireId(value, label) {
|
|
138
|
+
if (!value || value.length > MAX_FEEDBACK_ID_LENGTH || !/^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(value)) {
|
|
139
|
+
throw new RunFeedbackError(`${label} is invalid`, "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
140
|
+
}
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
function normalizeList(values, maximum, maxLength, label, ids = false) {
|
|
144
|
+
if (!values)
|
|
145
|
+
return [];
|
|
146
|
+
if (values.length > maximum)
|
|
147
|
+
throw new RunFeedbackError(`Too many ${label}s`, "ERR_PRISM_RUN_FEEDBACK_BOUNDS");
|
|
148
|
+
const result = values.map((value) => {
|
|
149
|
+
if (typeof value !== "string" || !value.trim() || value.length > maxLength || /[\r\n]/.test(value)) {
|
|
150
|
+
throw new RunFeedbackError(`${label} is invalid`, "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
151
|
+
}
|
|
152
|
+
return ids ? requireId(value, label) : value;
|
|
153
|
+
});
|
|
154
|
+
if (new Set(result).size !== result.length)
|
|
155
|
+
throw new RunFeedbackError(`Duplicate ${label}`, "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
function boundedLimit(value, fallback, hard, label) {
|
|
159
|
+
const resolved = value ?? fallback;
|
|
160
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1 || resolved > hard) {
|
|
161
|
+
throw new RunFeedbackError(`${label} must be an integer in [1, ${hard}]`, "ERR_PRISM_RUN_FEEDBACK_BOUNDS");
|
|
162
|
+
}
|
|
163
|
+
return resolved;
|
|
164
|
+
}
|
|
165
|
+
function pageLimit(value, maximum) {
|
|
166
|
+
if (value === undefined)
|
|
167
|
+
return Math.min(DEFAULT_FEEDBACK_PAGE_SIZE, maximum);
|
|
168
|
+
if (!Number.isSafeInteger(value) || value < 1)
|
|
169
|
+
throw new RunFeedbackError("limit must be a positive integer", "ERR_PRISM_RUN_FEEDBACK_BOUNDS");
|
|
170
|
+
return Math.min(value, maximum);
|
|
171
|
+
}
|
|
172
|
+
function assertBytes(value, maximum, label) {
|
|
173
|
+
if (value === undefined)
|
|
174
|
+
return;
|
|
175
|
+
let encoded;
|
|
176
|
+
try {
|
|
177
|
+
encoded = typeof value === "string" ? value : JSON.stringify(value);
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
throw new RunFeedbackError(`${label} must be JSON serializable`, "ERR_PRISM_RUN_FEEDBACK_VALIDATION");
|
|
181
|
+
}
|
|
182
|
+
if (new TextEncoder().encode(encoded).byteLength > maximum) {
|
|
183
|
+
throw new RunFeedbackError(`${label} exceeds ${maximum} bytes`, "ERR_PRISM_RUN_FEEDBACK_BOUNDS");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function matchesQuery(record, query) {
|
|
187
|
+
if (query.runId !== undefined && record.runId !== query.runId)
|
|
188
|
+
return false;
|
|
189
|
+
if (query.sessionId !== undefined && record.sessionId !== query.sessionId)
|
|
190
|
+
return false;
|
|
191
|
+
if (query.traceId !== undefined && record.traceId !== query.traceId)
|
|
192
|
+
return false;
|
|
193
|
+
if (query.rating !== undefined && record.rating !== query.rating)
|
|
194
|
+
return false;
|
|
195
|
+
if (query.scorerId !== undefined && !record.scorerIds.includes(query.scorerId))
|
|
196
|
+
return false;
|
|
197
|
+
if (query.evaluationId !== undefined && !record.evaluationIds.includes(query.evaluationId))
|
|
198
|
+
return false;
|
|
199
|
+
if (query.tag !== undefined && !record.tags.includes(query.tag))
|
|
200
|
+
return false;
|
|
201
|
+
if (query.fromCreatedAt !== undefined && record.createdAt < query.fromCreatedAt)
|
|
202
|
+
return false;
|
|
203
|
+
if (query.toCreatedAt !== undefined && record.createdAt > query.toCreatedAt)
|
|
204
|
+
return false;
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
function freezeRecord(record) {
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
...record,
|
|
210
|
+
tags: Object.freeze([...record.tags]),
|
|
211
|
+
scorerIds: Object.freeze([...record.scorerIds]),
|
|
212
|
+
evaluationIds: Object.freeze([...record.evaluationIds]),
|
|
213
|
+
metadata: record.metadata ? cloneFrozenJsonObject(record.metadata) : undefined,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function cloneFrozenJsonObject(value) {
|
|
217
|
+
const cloned = JSON.parse(JSON.stringify(value));
|
|
218
|
+
if (!cloned || typeof cloned !== "object" || Array.isArray(cloned))
|
|
219
|
+
throw new RunFeedbackError("metadata must be a JSON object");
|
|
220
|
+
return deepFreeze(cloned);
|
|
221
|
+
}
|
|
222
|
+
function deepFreeze(value) {
|
|
223
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
224
|
+
for (const child of Object.values(value))
|
|
225
|
+
deepFreeze(child);
|
|
226
|
+
Object.freeze(value);
|
|
227
|
+
}
|
|
228
|
+
return value;
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=feedback.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
export type * from "./contracts.js";
|
|
2
|
-
export { isSessionEntryKind, SESSION_APPEND_CONFLICT_CODE, SESSION_ENTRY_KINDS, SESSION_ENTRY_SCHEMA_VERSION, SessionAppendConflictError, isSessionAppendConflict } from "./contracts.js";
|
|
2
|
+
export { isSessionEntryKind, SESSION_APPEND_CONFLICT_CODE, SESSION_ENTRY_KINDS, SESSION_ENTRY_SCHEMA_VERSION, SessionAppendConflictError, isSessionAppendConflict, AgentRunError } from "./contracts.js";
|
|
3
3
|
export { createAgent, createAgentSession } from "./agents.js";
|
|
4
|
+
export { createMemoryRunFeedbackStore, prepareRunFeedback, requireRunFeedbackOwnership, runFeedbackPageLimit, RunFeedbackError, } from "./feedback.js";
|
|
5
|
+
export type { MemoryRunFeedbackStoreOptions, PrepareRunFeedbackOptions, RunFeedbackLimits, RunFeedbackRun, RunFeedbackRunResolver, } from "./feedback.js";
|
|
6
|
+
export { CHECKPOINT_CONFLICT_CODE, CheckpointConflictError, createMemoryCheckpointStore } from "./checkpoints.js";
|
|
7
|
+
export type { MemoryCheckpointStoreOptions } from "./checkpoints.js";
|
|
8
|
+
export { LEASE_CONFLICT_CODE, LeaseConflictError, createMemoryLeaseStore } from "./leases.js";
|
|
9
|
+
export { createEventMultiplexer } from "./event-multiplexer.js";
|
|
10
|
+
export type { EventMultiplexer, EventMultiplexerOptions, EventOverflowInfo, EventOverflowPolicy } from "./event-multiplexer.js";
|
|
4
11
|
export { applyCacheControl, cacheHitRate, cacheSavings, cacheUsageReport, mapCacheRetention, sanitizeCacheKey } from "./cache-helpers.js";
|
|
5
12
|
export type { ApplyCacheControlOptions, CacheControlledContentBlock, CacheControlledMessage, CacheControlValue, CacheUsageReport } from "./cache-helpers.js";
|
|
6
13
|
export { resolveAgentDefinition } from "./agent-definitions.js";
|
|
@@ -19,6 +26,8 @@ export type { ExtensionErrorPolicy, ExtensionEventBus, ExtensionEventHandler, Ex
|
|
|
19
26
|
export type { CredentialRecord, CredentialValueSource, MemoryCredentialStore } from "./credentials.js";
|
|
20
27
|
export { createModelRegistry } from "./models.js";
|
|
21
28
|
export { authMethodKey, defineProviderPackage, systemPromptContributionKey } from "./provider-packages.js";
|
|
29
|
+
export { assertStructuredOutputRequestSupported, DEFAULT_MAX_STRUCTURED_OUTPUT_NAME_LENGTH, DEFAULT_MAX_STRUCTURED_OUTPUT_SCHEMA_BYTES, modelSupportsStructuredOutput, resolveRunProviderOptions, StructuredOutputError, validateStructuredOutputOptions, } from "./structured-output.js";
|
|
30
|
+
export { createProviderTurnMetadata, readProviderHttpStatus } from "./observability.js";
|
|
22
31
|
export { createProviderRequestPolicyChain, createSessionCachePolicy, mergeProviderRequestOptions } from "./provider-request-policy.js";
|
|
23
32
|
export type { SessionCachePolicyOptions } from "./provider-request-policy.js";
|
|
24
33
|
export { composeSystemPrompt, mergeSystemPromptConfig } from "./system-prompts.js";
|
|
@@ -26,7 +35,10 @@ export type { ComposeSystemPromptOptions } from "./system-prompts.js";
|
|
|
26
35
|
export type { ModelRegistry, ModelRegistryOptions } from "./models.js";
|
|
27
36
|
export { definePrismManifest, parsePrismManifest } from "./manifests.js";
|
|
28
37
|
export type { ManifestContributionDeclaration, ManifestContributionKind, ManifestResourceDeclaration, PrismManifest } from "./manifests.js";
|
|
29
|
-
export {
|
|
38
|
+
export { assertDeclaredMediaTypeMatches, assertMediaBlocksWithinBounds, assertMessagesSupportModelCapabilities, assertModelSupportsContentBlocks, assertSsrfAllowedUrl, collectMessageContentBlocks, contentBlockInputModality, DEFAULT_MAX_AUDIO_DURATION_MS, DEFAULT_MAX_MEDIA_ITEM_BYTES, DEFAULT_MAX_MEDIA_ITEMS_PER_REQUEST, DEFAULT_MAX_MEDIA_REQUEST_BYTES, DEFAULT_MEDIA_FETCH_TIMEOUT_MS, loadBoundedBinaryResource, MediaContentError, MODEL_INPUT_CAPABILITIES, resolveMediaContentBlock, resolveMediaContentBlocks, sniffMediaMimeType, UnsupportedModalityError, } from "./content.js";
|
|
39
|
+
export type { AudioContent, DocumentContent, FileContent, MediaContentBlock, MediaContentBounds, MediaHostAddress, MediaHostnameResolver, MediaMimePolicy, MediaUrlRequest, MediaUrlRequester, ModelInputCapability, ResolvedMediaContent, ResolveMediaContentOptions, SsrfPolicy, } from "./content.js";
|
|
40
|
+
export { loadBinaryResource, loadJsonResource, loadManifestResource, loadTextResource } from "./resources.js";
|
|
41
|
+
export type { LoadBinaryResourceOptions } from "./resources.js";
|
|
30
42
|
export { createChainedSettingsProvider, createStaticSettingsProvider } from "./settings.js";
|
|
31
43
|
export { createMiddlewareRegistry } from "./middleware.js";
|
|
32
44
|
export type { Middleware, MiddlewareHookName, MiddlewareNext, MiddlewareRegistry, MiddlewareRegistryOptions } from "./middleware.js";
|
|
@@ -44,14 +56,16 @@ export { createSecretRedactor, errorToErrorInfo, redactAgentEvent, redactMessage
|
|
|
44
56
|
export type { SecretRedactor } from "./redaction.js";
|
|
45
57
|
export { assertPermission, assertTrusted, checkPermission, createStaticPermissionPolicy, createStaticTrustPolicy, denialToErrorInfo, isTrusted, PermissionDeniedError, TrustDeniedError } from "./security.js";
|
|
46
58
|
export type { PermissionDecision, PermissionPolicy, PermissionRequest, TrustDecision, TrustPolicy, TrustRequest } from "./security.js";
|
|
59
|
+
export { applyExecutionDecision, assertExecutionAllowed, checkExecution, ExecutionDeniedError } from "./execution-policy.js";
|
|
60
|
+
export type { ExecutionAction, ExecutionDecision, ExecutionPolicy, ExecutionRisk } from "./execution-policy.js";
|
|
47
61
|
export { createSkillRegistry, resolveActiveSkills } from "./skills.js";
|
|
48
62
|
export type { ResolveActiveSkillsOptions, SkillRegistryOptions } from "./skills.js";
|
|
49
63
|
export { resolveInstructionInjectors, runInstructionInjectors } from "./instruction-injection.js";
|
|
50
64
|
export type { ResolveInstructionInjectorsOptions } from "./instruction-injection.js";
|
|
51
|
-
export { createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
|
|
52
|
-
export type { DispatchToolCallOptions, ToolFilter, ToolFilterInput, ToolRegistryOptions, ToolValidator } from "./tools.js";
|
|
65
|
+
export { createToolRegistry, dispatchToolCall, filterTools, createToolParameterValidator } from "./tools.js";
|
|
66
|
+
export type { DispatchToolCallOptions, ToolArgumentValidationError, ToolArgumentValidationResult, ToolArgumentValidator, ToolFilter, ToolFilterInput, ToolParameterValidatorOptions, ToolRegistryOptions, ToolValidator, } from "./tools.js";
|
|
53
67
|
export type { DuplicateRegistrationOptions, DuplicateRegistrationPolicy } from "./registry-options.js";
|
|
54
|
-
export { generateValidateReviseLoop, isAgentLoopOptions, resolveLoop, singleShotLoop } from "./agent-loops.js";
|
|
68
|
+
export { dispatchToolCallsInOrder, generateValidateReviseLoop, isAgentLoopOptions, resolveLoop, resolveToolConcurrency, singleShotLoop } from "./agent-loops.js";
|
|
55
69
|
export declare const name = "prism";
|
|
56
|
-
export declare const version = "0.0.
|
|
70
|
+
export declare const version = "0.0.5";
|
|
57
71
|
export declare const description = "Agent harness for AI providers, agents, sessions, and tools.";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
export { isSessionEntryKind, SESSION_APPEND_CONFLICT_CODE, SESSION_ENTRY_KINDS, SESSION_ENTRY_SCHEMA_VERSION, SessionAppendConflictError, isSessionAppendConflict } from "./contracts.js";
|
|
1
|
+
export { isSessionEntryKind, SESSION_APPEND_CONFLICT_CODE, SESSION_ENTRY_KINDS, SESSION_ENTRY_SCHEMA_VERSION, SessionAppendConflictError, isSessionAppendConflict, AgentRunError } from "./contracts.js";
|
|
2
2
|
export { createAgent, createAgentSession } from "./agents.js";
|
|
3
|
+
export { createMemoryRunFeedbackStore, prepareRunFeedback, requireRunFeedbackOwnership, runFeedbackPageLimit, RunFeedbackError, } from "./feedback.js";
|
|
4
|
+
export { CHECKPOINT_CONFLICT_CODE, CheckpointConflictError, createMemoryCheckpointStore } from "./checkpoints.js";
|
|
5
|
+
export { LEASE_CONFLICT_CODE, LeaseConflictError, createMemoryLeaseStore } from "./leases.js";
|
|
6
|
+
export { createEventMultiplexer } from "./event-multiplexer.js";
|
|
3
7
|
export { applyCacheControl, cacheHitRate, cacheSavings, cacheUsageReport, mapCacheRetention, sanitizeCacheKey } from "./cache-helpers.js";
|
|
4
8
|
export { resolveAgentDefinition } from "./agent-definitions.js";
|
|
5
9
|
export { parseSkillFile, parseAgentFile } from "./contribution-parsing.js";
|
|
@@ -11,10 +15,13 @@ export { createChainedCredentialResolver, createEnvCredentialResolver, createExp
|
|
|
11
15
|
export { createExtensionEventBus, createExtensionKernel } from "./extensions.js";
|
|
12
16
|
export { createModelRegistry } from "./models.js";
|
|
13
17
|
export { authMethodKey, defineProviderPackage, systemPromptContributionKey } from "./provider-packages.js";
|
|
18
|
+
export { assertStructuredOutputRequestSupported, DEFAULT_MAX_STRUCTURED_OUTPUT_NAME_LENGTH, DEFAULT_MAX_STRUCTURED_OUTPUT_SCHEMA_BYTES, modelSupportsStructuredOutput, resolveRunProviderOptions, StructuredOutputError, validateStructuredOutputOptions, } from "./structured-output.js";
|
|
19
|
+
export { createProviderTurnMetadata, readProviderHttpStatus } from "./observability.js";
|
|
14
20
|
export { createProviderRequestPolicyChain, createSessionCachePolicy, mergeProviderRequestOptions } from "./provider-request-policy.js";
|
|
15
21
|
export { composeSystemPrompt, mergeSystemPromptConfig } from "./system-prompts.js";
|
|
16
22
|
export { definePrismManifest, parsePrismManifest } from "./manifests.js";
|
|
17
|
-
export {
|
|
23
|
+
export { assertDeclaredMediaTypeMatches, assertMediaBlocksWithinBounds, assertMessagesSupportModelCapabilities, assertModelSupportsContentBlocks, assertSsrfAllowedUrl, collectMessageContentBlocks, contentBlockInputModality, DEFAULT_MAX_AUDIO_DURATION_MS, DEFAULT_MAX_MEDIA_ITEM_BYTES, DEFAULT_MAX_MEDIA_ITEMS_PER_REQUEST, DEFAULT_MAX_MEDIA_REQUEST_BYTES, DEFAULT_MEDIA_FETCH_TIMEOUT_MS, loadBoundedBinaryResource, MediaContentError, MODEL_INPUT_CAPABILITIES, resolveMediaContentBlock, resolveMediaContentBlocks, sniffMediaMimeType, UnsupportedModalityError, } from "./content.js";
|
|
24
|
+
export { loadBinaryResource, loadJsonResource, loadManifestResource, loadTextResource } from "./resources.js";
|
|
18
25
|
export { createChainedSettingsProvider, createStaticSettingsProvider } from "./settings.js";
|
|
19
26
|
export { createMiddlewareRegistry } from "./middleware.js";
|
|
20
27
|
export { assembleProviderInput, createDefaultInputBuilder, createDefaultPromptBuilder, renderPromptTemplate, resolveContextProviders } from "./input.js";
|
|
@@ -24,11 +31,12 @@ export { providerContentDelta, providerDone, providerError, providerTextDelta, p
|
|
|
24
31
|
export { createProviderRegistry, createProviderResolver } from "./providers.js";
|
|
25
32
|
export { createSecretRedactor, errorToErrorInfo, redactAgentEvent, redactMessage, redactProviderRequest, redactRunLedgerRecord, redactSecrets, redactSessionEntry } from "./redaction.js";
|
|
26
33
|
export { assertPermission, assertTrusted, checkPermission, createStaticPermissionPolicy, createStaticTrustPolicy, denialToErrorInfo, isTrusted, PermissionDeniedError, TrustDeniedError } from "./security.js";
|
|
34
|
+
export { applyExecutionDecision, assertExecutionAllowed, checkExecution, ExecutionDeniedError } from "./execution-policy.js";
|
|
27
35
|
export { createSkillRegistry, resolveActiveSkills } from "./skills.js";
|
|
28
36
|
export { resolveInstructionInjectors, runInstructionInjectors } from "./instruction-injection.js";
|
|
29
|
-
export { createToolRegistry, dispatchToolCall, filterTools } from "./tools.js";
|
|
30
|
-
export { generateValidateReviseLoop, isAgentLoopOptions, resolveLoop, singleShotLoop } from "./agent-loops.js";
|
|
37
|
+
export { createToolRegistry, dispatchToolCall, filterTools, createToolParameterValidator } from "./tools.js";
|
|
38
|
+
export { dispatchToolCallsInOrder, generateValidateReviseLoop, isAgentLoopOptions, resolveLoop, resolveToolConcurrency, singleShotLoop } from "./agent-loops.js";
|
|
31
39
|
export const name = "prism";
|
|
32
|
-
export const version = "0.0.
|
|
40
|
+
export const version = "0.0.5";
|
|
33
41
|
export const description = "Agent harness for AI providers, agents, sessions, and tools.";
|
|
34
42
|
//# sourceMappingURL=index.js.map
|
package/dist/input.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { redactMessage } from "./redaction.js";
|
|
2
|
+
import { assertMessagesSupportModelCapabilities } from "./content.js";
|
|
2
3
|
import { loadTextResource } from "./resources.js";
|
|
3
4
|
import { composeSystemPrompt } from "./system-prompts.js";
|
|
4
5
|
import { runInstructionInjectors } from "./instruction-injection.js";
|
|
@@ -118,6 +119,7 @@ export async function assembleProviderInput(options) {
|
|
|
118
119
|
signal: options.signal,
|
|
119
120
|
};
|
|
120
121
|
const providerMessages = await promptBuilder.build({ ...promptRequest, tools: options.tools });
|
|
122
|
+
assertMessagesSupportModelCapabilities(options.model, providerMessages);
|
|
121
123
|
return {
|
|
122
124
|
model: options.model,
|
|
123
125
|
messages: providerMessages,
|
|
@@ -232,7 +234,15 @@ function blockText(block) {
|
|
|
232
234
|
return `${part.name}(${JSON.stringify(part.arguments)})`;
|
|
233
235
|
if (part.type === "tool_call_delta")
|
|
234
236
|
return `${part.name ?? "tool"}(${part.argumentsText ?? ""})`;
|
|
235
|
-
|
|
237
|
+
if (part.type === "image")
|
|
238
|
+
return part.url ?? part.resourceUri ?? part.mimeType ?? "[image]";
|
|
239
|
+
if (part.type === "audio")
|
|
240
|
+
return part.transcript ?? part.name ?? part.url ?? part.resourceUri ?? part.mediaType ?? "[audio]";
|
|
241
|
+
if (part.type === "file")
|
|
242
|
+
return part.name ?? part.url ?? part.resourceUri ?? part.mediaType ?? "[file]";
|
|
243
|
+
if (part.type === "document")
|
|
244
|
+
return part.transcript ?? part.name ?? part.url ?? part.resourceUri ?? part.mediaType ?? "[document]";
|
|
245
|
+
return "[content]";
|
|
236
246
|
}).join("\n");
|
|
237
247
|
}
|
|
238
248
|
function templateValue(value) {
|
package/dist/leases.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LeaseStore } from "./contracts.js";
|
|
2
|
+
export declare const LEASE_CONFLICT_CODE = "ERR_PRISM_LEASE_CONFLICT";
|
|
3
|
+
export declare class LeaseConflictError extends Error {
|
|
4
|
+
readonly code = "ERR_PRISM_LEASE_CONFLICT";
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/** In-process reference implementation. Durable adapters provide cross-process exclusion. */
|
|
8
|
+
export declare function createMemoryLeaseStore(): LeaseStore;
|
package/dist/leases.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export const LEASE_CONFLICT_CODE = "ERR_PRISM_LEASE_CONFLICT";
|
|
2
|
+
export class LeaseConflictError extends Error {
|
|
3
|
+
code = LEASE_CONFLICT_CODE;
|
|
4
|
+
constructor(message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "LeaseConflictError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** In-process reference implementation. Durable adapters provide cross-process exclusion. */
|
|
10
|
+
export function createMemoryLeaseStore() {
|
|
11
|
+
const records = new Map();
|
|
12
|
+
return {
|
|
13
|
+
async tryAcquireLease(input) {
|
|
14
|
+
validateAcquire(input);
|
|
15
|
+
const id = keyOf(input);
|
|
16
|
+
const current = records.get(id);
|
|
17
|
+
if (current)
|
|
18
|
+
assertOwnership(input, current);
|
|
19
|
+
const now = Date.now();
|
|
20
|
+
if (current && Date.parse(current.expiresAt) > now)
|
|
21
|
+
return null;
|
|
22
|
+
const timestamp = new Date(now).toISOString();
|
|
23
|
+
const record = {
|
|
24
|
+
namespace: input.namespace,
|
|
25
|
+
key: input.key,
|
|
26
|
+
ownerId: input.ownerId,
|
|
27
|
+
token: crypto.randomUUID(),
|
|
28
|
+
fencingToken: (current?.fencingToken ?? 0) + 1,
|
|
29
|
+
acquiredAt: timestamp,
|
|
30
|
+
expiresAt: new Date(now + input.ttlMs).toISOString(),
|
|
31
|
+
updatedAt: timestamp,
|
|
32
|
+
...ownership(input),
|
|
33
|
+
};
|
|
34
|
+
records.set(id, record);
|
|
35
|
+
return record;
|
|
36
|
+
},
|
|
37
|
+
async renewLease(input) {
|
|
38
|
+
validateClaim(input, true);
|
|
39
|
+
const current = records.get(keyOf(input));
|
|
40
|
+
if (!current)
|
|
41
|
+
return null;
|
|
42
|
+
assertOwnership(input, current);
|
|
43
|
+
const now = Date.now();
|
|
44
|
+
if (current.ownerId !== input.ownerId || current.token !== input.token || Date.parse(current.expiresAt) <= now)
|
|
45
|
+
return null;
|
|
46
|
+
const record = {
|
|
47
|
+
...current,
|
|
48
|
+
expiresAt: new Date(now + input.ttlMs).toISOString(),
|
|
49
|
+
updatedAt: new Date(now).toISOString(),
|
|
50
|
+
};
|
|
51
|
+
records.set(keyOf(input), record);
|
|
52
|
+
return record;
|
|
53
|
+
},
|
|
54
|
+
async releaseLease(input) {
|
|
55
|
+
validateClaim(input, false);
|
|
56
|
+
const current = records.get(keyOf(input));
|
|
57
|
+
if (!current)
|
|
58
|
+
return false;
|
|
59
|
+
assertOwnership(input, current);
|
|
60
|
+
if (current.ownerId !== input.ownerId || current.token !== input.token)
|
|
61
|
+
return false;
|
|
62
|
+
const now = new Date().toISOString();
|
|
63
|
+
records.set(keyOf(input), { ...current, expiresAt: now, updatedAt: now });
|
|
64
|
+
return true;
|
|
65
|
+
},
|
|
66
|
+
async getLease(input) {
|
|
67
|
+
throwIfAborted(input.signal);
|
|
68
|
+
const current = records.get(keyOf(input));
|
|
69
|
+
if (!current)
|
|
70
|
+
return null;
|
|
71
|
+
assertOwnership(input, current);
|
|
72
|
+
return Date.parse(current.expiresAt) > Date.now() ? current : null;
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function keyOf(input) {
|
|
77
|
+
return `${input.namespace}\0${input.key}`;
|
|
78
|
+
}
|
|
79
|
+
function ownership(input) {
|
|
80
|
+
return {
|
|
81
|
+
...(input.tenantId === undefined ? {} : { tenantId: input.tenantId }),
|
|
82
|
+
...(input.accountId === undefined ? {} : { accountId: input.accountId }),
|
|
83
|
+
...(input.userId === undefined ? {} : { userId: input.userId }),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function assertOwnership(expected, actual) {
|
|
87
|
+
if (expected.tenantId !== actual.tenantId || expected.accountId !== actual.accountId || expected.userId !== actual.userId) {
|
|
88
|
+
throw new LeaseConflictError("Lease ownership mismatch");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function validateKey(input) {
|
|
92
|
+
throwIfAborted(input.signal);
|
|
93
|
+
if (!input.namespace || !input.key)
|
|
94
|
+
throw new LeaseConflictError("Lease namespace and key are required");
|
|
95
|
+
}
|
|
96
|
+
function validateAcquire(input) {
|
|
97
|
+
validateKey(input);
|
|
98
|
+
if (!input.ownerId || !Number.isSafeInteger(input.ttlMs) || input.ttlMs < 1)
|
|
99
|
+
throw new LeaseConflictError("Lease ownerId and positive ttlMs are required");
|
|
100
|
+
}
|
|
101
|
+
function validateClaim(input, requireTtl) {
|
|
102
|
+
validateKey(input);
|
|
103
|
+
if (!input.ownerId || !input.token || (requireTtl && (!Number.isSafeInteger(input.ttlMs) || input.ttlMs < 1))) {
|
|
104
|
+
throw new LeaseConflictError("Lease ownerId, token, and positive ttlMs are required");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function throwIfAborted(signal) {
|
|
108
|
+
if (signal?.aborted)
|
|
109
|
+
throw signal.reason ?? new DOMException("Aborted", "AbortError");
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=leases.js.map
|
|
@@ -7,6 +7,7 @@ import { assertPermission, isTrusted } from "../security.js";
|
|
|
7
7
|
import { isPathInsideReal } from "./trust.js";
|
|
8
8
|
import { readOptionalFile } from "./contribution-discovery.js";
|
|
9
9
|
import { createSkillRegistry } from "../skills.js";
|
|
10
|
+
import { isNodeErrorCode } from "./config.js";
|
|
10
11
|
const defaultInclude = {
|
|
11
12
|
systemPrompt: true,
|
|
12
13
|
agentPrompt: true,
|
|
@@ -329,7 +330,7 @@ async function listSubdirs(dir) {
|
|
|
329
330
|
return out;
|
|
330
331
|
}
|
|
331
332
|
catch (error) {
|
|
332
|
-
if (
|
|
333
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
333
334
|
return [];
|
|
334
335
|
throw error;
|
|
335
336
|
}
|
|
@@ -339,14 +340,11 @@ async function readOptional(read, path) {
|
|
|
339
340
|
return await read(path);
|
|
340
341
|
}
|
|
341
342
|
catch (error) {
|
|
342
|
-
if (
|
|
343
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
343
344
|
return undefined;
|
|
344
345
|
throw error;
|
|
345
346
|
}
|
|
346
347
|
}
|
|
347
|
-
function isMissingFile(error) {
|
|
348
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
349
|
-
}
|
|
350
348
|
const NAME_RE = /^[A-Za-z0-9 _-]+$/;
|
|
351
349
|
function parentDirName(path) {
|
|
352
350
|
const parts = path.split(/[/\\]+/).filter(Boolean);
|
package/dist/node/config.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ export interface NodeConfigFile {
|
|
|
7
7
|
export declare function defaultUserConfigPath(appName?: string): string;
|
|
8
8
|
export declare function readConfigFile(path: string): Promise<ConfigLayer["config"]>;
|
|
9
9
|
export declare function loadConfigFiles(files: readonly NodeConfigFile[]): Promise<ConfigLayer[]>;
|
|
10
|
+
export declare function isNodeErrorCode(error: unknown, code: string): boolean;
|
package/dist/node/config.js
CHANGED
|
@@ -11,6 +11,8 @@ export async function readConfigFile(path) {
|
|
|
11
11
|
text = await readFile(path, "utf8");
|
|
12
12
|
}
|
|
13
13
|
catch (error) {
|
|
14
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
15
|
+
throw error;
|
|
14
16
|
throw new Error(`Failed to read config ${path}: ${errorMessage(error)}`);
|
|
15
17
|
}
|
|
16
18
|
let parsed;
|
|
@@ -35,15 +37,15 @@ export async function loadConfigFiles(files) {
|
|
|
35
37
|
layers.push({ name: file.name, config: await readConfigFile(file.path) });
|
|
36
38
|
}
|
|
37
39
|
catch (error) {
|
|
38
|
-
if (file.optional &&
|
|
40
|
+
if (file.optional && isNodeErrorCode(error, "ENOENT"))
|
|
39
41
|
continue;
|
|
40
42
|
throw error;
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
return layers;
|
|
44
46
|
}
|
|
45
|
-
function
|
|
46
|
-
return error instanceof Error && error.
|
|
47
|
+
export function isNodeErrorCode(error, code) {
|
|
48
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
47
49
|
}
|
|
48
50
|
function errorMessage(error) {
|
|
49
51
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -4,6 +4,7 @@ import { isJsonObject } from "../config.js";
|
|
|
4
4
|
import { assertPermission } from "../security.js";
|
|
5
5
|
import { isPathInsideReal } from "./trust.js";
|
|
6
6
|
import { parseSkillFile } from "../contribution-parsing.js";
|
|
7
|
+
import { isNodeErrorCode } from "./config.js";
|
|
7
8
|
/**
|
|
8
9
|
* Discover contributions on disk. Scans the workspace `.agents/` tree only;
|
|
9
10
|
* no global root. One `readdir` per kind-root; no `import()`. Inert output —
|
|
@@ -34,7 +35,7 @@ async function scanKindRoot(root, kind, options) {
|
|
|
34
35
|
names = await readdir(kindDir);
|
|
35
36
|
}
|
|
36
37
|
catch (error) {
|
|
37
|
-
if (
|
|
38
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
38
39
|
return []; // missing kind root is normal
|
|
39
40
|
throw error;
|
|
40
41
|
}
|
|
@@ -46,7 +47,7 @@ async function scanKindRoot(root, kind, options) {
|
|
|
46
47
|
isDir = (await stat(dir)).isDirectory();
|
|
47
48
|
}
|
|
48
49
|
catch (error) {
|
|
49
|
-
if (
|
|
50
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
50
51
|
continue;
|
|
51
52
|
throw error;
|
|
52
53
|
}
|
|
@@ -91,14 +92,13 @@ async function readManifestEntry(dir, fallbackName, kind, origin) {
|
|
|
91
92
|
const declaration = parseManifestDeclaration(text, path, kind, fallbackName);
|
|
92
93
|
return { kind, name: declaration.name, origin, path, declaration };
|
|
93
94
|
}
|
|
94
|
-
// ponytail: Phase 31 — exported so the system/project prompt file loader reuses
|
|
95
|
-
// ENOENT-tolerant read instead of duplicating it. isMissingFile stays private (only readOptionalFile needs it).
|
|
95
|
+
// ponytail: Phase 31 — exported so the system/project prompt file loader reuses this ENOENT-tolerant read.
|
|
96
96
|
export async function readOptionalFile(path) {
|
|
97
97
|
try {
|
|
98
98
|
return await readFile(path, "utf8");
|
|
99
99
|
}
|
|
100
100
|
catch (error) {
|
|
101
|
-
if (
|
|
101
|
+
if (isNodeErrorCode(error, "ENOENT"))
|
|
102
102
|
return undefined;
|
|
103
103
|
throw error;
|
|
104
104
|
}
|
|
@@ -106,9 +106,6 @@ export async function readOptionalFile(path) {
|
|
|
106
106
|
// --- Internal helpers. ---
|
|
107
107
|
// ponytail: parseSkillFile/parseAgentFile live in ../contribution-parsing.ts (core, fs-free); this
|
|
108
108
|
// Node module owns directory walking + manifest.json parsing only.
|
|
109
|
-
function isMissingFile(error) {
|
|
110
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
111
|
-
}
|
|
112
109
|
function parseManifestDeclaration(text, path, dirKind, fallbackName) {
|
|
113
110
|
let parsed;
|
|
114
111
|
try {
|