@arnilo/prism 0.0.96 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +285 -2
- package/README.md +17 -3
- package/dist/agent-definitions.js +2 -3
- package/dist/agent-event-source.d.ts +11 -0
- package/dist/agent-event-source.js +512 -0
- package/dist/agent-loops.d.ts +5 -0
- package/dist/agent-loops.js +99 -14
- package/dist/agent-run-lifecycle.d.ts +5 -2
- package/dist/agent-run-lifecycle.js +18 -2
- package/dist/agent-run-state.d.ts +27 -1
- package/dist/agent-run-state.js +113 -7
- package/dist/agents.d.ts +3 -1
- package/dist/agents.js +1255 -129
- package/dist/artifacts.d.ts +132 -0
- package/dist/artifacts.js +44 -0
- 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.d.ts +67 -0
- package/dist/context-budget.js +288 -0
- package/dist/contracts.d.ts +590 -8
- package/dist/contracts.js +142 -1
- package/dist/contribution-parsing.js +6 -2
- package/dist/contributions.d.ts +2 -0
- package/dist/contributions.js +3 -0
- package/dist/conversations.d.ts +50 -0
- package/dist/conversations.js +98 -0
- package/dist/credentials.d.ts +22 -2
- package/dist/credentials.js +18 -3
- package/dist/devices.d.ts +94 -0
- package/dist/devices.js +138 -0
- package/dist/event-multiplexer.js +18 -4
- package/dist/extensions.d.ts +18 -1
- package/dist/extensions.js +79 -6
- package/dist/feedback.js +12 -10
- package/dist/guardrails.d.ts +1 -1
- package/dist/guardrails.js +26 -17
- package/dist/identity.d.ts +92 -0
- package/dist/identity.js +265 -0
- package/dist/index.d.ts +94 -72
- package/dist/index.js +48 -36
- package/dist/input.d.ts +10 -1
- package/dist/input.js +152 -52
- 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 +13 -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.d.ts +103 -0
- package/dist/persistence-lifecycle.js +202 -0
- package/dist/provider-events.d.ts +1 -0
- package/dist/provider-events.js +6 -1
- package/dist/provider-request-policy.js +3 -4
- package/dist/providers/media.d.ts +1 -1
- package/dist/providers/openai-compatible.d.ts +46 -1
- package/dist/providers/openai-compatible.js +123 -53
- package/dist/providers/openai-primitives.js +10 -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 +55 -11
- 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 +8 -2
- package/dist/security.js +7 -2
- package/dist/session-stores.d.ts +7 -2
- package/dist/session-stores.js +195 -21
- package/dist/skill-disclosure.d.ts +35 -0
- package/dist/skill-disclosure.js +101 -0
- package/dist/skill-load.d.ts +25 -0
- package/dist/skill-load.js +112 -0
- package/dist/structured-output.d.ts +5 -1
- package/dist/structured-output.js +20 -2
- package/dist/system-prompts.js +7 -2
- package/dist/testing/agent-event-source-conformance.d.ts +4 -0
- package/dist/testing/agent-event-source-conformance.js +54 -0
- 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.d.ts +2 -2
- package/dist/testing/persistence-schema.js +280 -35
- package/dist/testing/provider-conformance.js +3 -3
- package/dist/testing/run-ledger-conformance.js +1 -1
- package/dist/testing/session-store-conformance.d.ts +6 -0
- package/dist/testing/session-store-conformance.js +37 -2
- package/dist/testing/tool-conformance.js +30 -5
- package/dist/testing/tool-effect-store-conformance.d.ts +9 -0
- package/dist/testing/tool-effect-store-conformance.js +85 -0
- package/dist/thinking.js +4 -1
- package/dist/tool-effects.d.ts +15 -0
- package/dist/tool-effects.js +352 -0
- package/dist/tool-result-fold.d.ts +40 -0
- package/dist/tool-result-fold.js +176 -0
- package/dist/tools.d.ts +8 -3
- package/dist/tools.js +248 -13
- package/docs/0.1.0-readiness.md +202 -0
- package/docs/a2a.md +33 -2
- package/docs/acp.md +126 -0
- package/docs/ag-ui-adoption.md +77 -0
- package/docs/ag-ui.md +225 -0
- package/docs/agent-events.md +34 -3
- package/docs/agent-identity.md +144 -0
- package/docs/agent-loops.md +17 -2
- package/docs/agent-session-runtime.md +21 -4
- package/docs/browser-automation.md +5 -0
- package/docs/caveman.md +129 -0
- package/docs/cli-rpc.md +3 -6
- package/docs/coding-agent-tools.md +229 -25
- package/docs/coding-security.md +77 -11
- package/docs/compaction-and-retry.md +5 -2
- package/docs/compaction-llm.md +20 -1
- package/docs/compaction-observational-memory.md +52 -8
- package/docs/context-and-skills.md +94 -7
- package/docs/contribution-registries.md +1 -0
- package/docs/conversations.md +135 -0
- package/docs/credential-storage.md +34 -1
- package/docs/credentials-and-redaction.md +11 -1
- package/docs/database-persistence.md +27 -7
- package/docs/device-adapters.md +97 -0
- package/docs/enterprise-postgres-state.md +178 -0
- package/docs/evaluations.md +14 -1
- package/docs/extensions.md +4 -1
- package/docs/forge-integration.md +113 -0
- package/docs/guardrails.md +16 -2
- package/docs/host-security.md +35 -4
- package/docs/index.md +69 -37
- package/docs/input-and-prompt-assembly.md +8 -7
- package/docs/language-intelligence.md +162 -0
- package/docs/mcp-tools.md +62 -5
- package/docs/middleware-hooks.md +2 -2
- package/docs/migration.md +423 -2
- package/docs/model-routing.md +111 -0
- package/docs/multimodal-content.md +8 -5
- package/docs/node-jsonl-session-store.md +1 -1
- package/docs/observability.md +2 -0
- package/docs/openapi-tools.md +56 -0
- package/docs/performance.md +282 -0
- package/docs/policy-and-audit.md +171 -0
- package/docs/ponytail.md +127 -0
- package/docs/postgres-persistence.md +8 -4
- package/docs/process-sessions.md +147 -0
- package/docs/provider-caching.md +13 -1
- package/docs/provider-conformance.md +29 -5
- package/docs/provider-packages.md +43 -2
- package/docs/provider-request-policies.md +2 -0
- package/docs/providers/ai-sdk.md +24 -7
- package/docs/providers/alibaba.md +179 -0
- package/docs/providers/anthropic.md +93 -0
- package/docs/providers/azure.md +74 -0
- package/docs/providers/bedrock.md +72 -0
- package/docs/providers/google.md +89 -0
- package/docs/providers/ollama.md +166 -0
- package/docs/providers/openai-compatible.md +31 -2
- package/docs/providers/openai.md +24 -5
- package/docs/providers/openrouter.md +2 -0
- package/docs/providers/vertex.md +71 -0
- package/docs/public-contracts.md +61 -4
- package/docs/rag.md +41 -12
- package/docs/release-and-install.md +323 -206
- package/docs/resource-loading.md +3 -0
- package/docs/runs-and-usage.md +3 -0
- package/docs/server.md +44 -6
- package/docs/session-store-conformance.md +2 -0
- package/docs/session-stores.md +41 -2
- package/docs/sqlite-persistence.md +11 -3
- package/docs/structured-output.md +7 -1
- package/docs/supervisors.md +8 -0
- package/docs/tool-effects.md +95 -0
- package/docs/tools.md +5 -0
- package/docs/work-artifacts-and-review.md +102 -0
- package/docs/work-connectors.md +32 -0
- package/docs/work-tools.md +137 -0
- package/docs/workflows.md +6 -0
- package/docs/working-and-semantic-memory.md +40 -7
- package/package.json +30 -8
- package/templates/init/providers.json +22 -0
- 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/dist/input.js
CHANGED
|
@@ -1,26 +1,19 @@
|
|
|
1
|
-
import { redactMessage } from "./redaction.js";
|
|
2
1
|
import { assertMessagesSupportModelCapabilities } from "./content.js";
|
|
2
|
+
import { applyContextBudget, CONTEXT_BUDGET_REPORT_METADATA_KEY } from "./context-budget.js";
|
|
3
|
+
import { runInstructionInjectors } from "./instruction-injection.js";
|
|
4
|
+
import { redactMessage } from "./redaction.js";
|
|
3
5
|
import { loadTextResource } from "./resources.js";
|
|
6
|
+
import { skillMessages as buildSkillMessages } from "./skill-disclosure.js";
|
|
7
|
+
import { foldToolResultHistory, foldToolResults } from "./tool-result-fold.js";
|
|
4
8
|
import { composeSystemPrompt } from "./system-prompts.js";
|
|
5
|
-
import { runInstructionInjectors } from "./instruction-injection.js";
|
|
6
9
|
export function createDefaultInputBuilder() {
|
|
7
10
|
return {
|
|
8
11
|
name: "default-input",
|
|
9
12
|
async build(input, context = {}) {
|
|
10
|
-
const groups =
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
...customInstructionMessages(context.instructions),
|
|
15
|
-
],
|
|
16
|
-
summaries: summaryMessages(context.summaries),
|
|
17
|
-
history: [...(context.history ?? [])],
|
|
18
|
-
input: inputMessages(input),
|
|
19
|
-
attachments: await attachmentMessages(context),
|
|
20
|
-
toolResults: toolResultMessages(context.toolResults),
|
|
21
|
-
};
|
|
22
|
-
const messages = flattenInputGroups(groups, context.inputLayout ?? "legacy");
|
|
23
|
-
return context.middleware ? context.middleware.run("input_assembly", messages) : messages;
|
|
13
|
+
const groups = await buildDefaultInputMessageGroups(input, context);
|
|
14
|
+
// `input_assembly` middleware is applied by assembleProviderInput after build(),
|
|
15
|
+
// never here: builders must not be a security seam.
|
|
16
|
+
return flattenInputGroups(groups, context.inputLayout ?? "cache_aware");
|
|
24
17
|
},
|
|
25
18
|
};
|
|
26
19
|
}
|
|
@@ -28,13 +21,13 @@ export async function resolveContextProviders(options) {
|
|
|
28
21
|
const blocks = [];
|
|
29
22
|
for (const provider of options.providers ?? []) {
|
|
30
23
|
throwIfAborted(options.signal);
|
|
31
|
-
blocks.push(...await provider.resolve({
|
|
24
|
+
blocks.push(...(await provider.resolve({
|
|
32
25
|
sessionId: options.sessionId,
|
|
33
26
|
runId: options.runId,
|
|
34
27
|
messages: options.messages,
|
|
35
28
|
metadata: options.metadata,
|
|
36
29
|
signal: options.signal,
|
|
37
|
-
}));
|
|
30
|
+
})));
|
|
38
31
|
}
|
|
39
32
|
// ponytail: injector blocks after host+skill provider blocks (split by origin if per-block ordering matters).
|
|
40
33
|
if (options.injectedBlocks)
|
|
@@ -45,10 +38,17 @@ export function createDefaultPromptBuilder() {
|
|
|
45
38
|
return {
|
|
46
39
|
name: "default-prompt",
|
|
47
40
|
async build(request) {
|
|
41
|
+
// Tool-capable models receive schemas via request.tools; the text list only serves
|
|
42
|
+
// text-only (or unknown-capability) models — duplicating it doubles tool tokens per turn.
|
|
43
|
+
const tools = request.model?.capabilities?.tools === true ? undefined : request.tools;
|
|
48
44
|
return [
|
|
49
45
|
...contextMessages(request.context),
|
|
50
|
-
...
|
|
51
|
-
|
|
46
|
+
...buildSkillMessages(request.skills, {
|
|
47
|
+
disclosure: request.skillsDisclosure,
|
|
48
|
+
loaded: request.loadedSkills,
|
|
49
|
+
demotedBodies: request.demotedSkillBodies?.length ? new Set(request.demotedSkillBodies) : undefined,
|
|
50
|
+
}),
|
|
51
|
+
...toolMessages(tools),
|
|
52
52
|
...request.messages,
|
|
53
53
|
];
|
|
54
54
|
},
|
|
@@ -56,7 +56,7 @@ export function createDefaultPromptBuilder() {
|
|
|
56
56
|
}
|
|
57
57
|
export function renderPromptTemplate(template, variables, options = {}) {
|
|
58
58
|
return template.replace(/\{\{\s*([A-Za-z0-9_]+)\s*\}\}/g, (match, name) => {
|
|
59
|
-
if (!Object.
|
|
59
|
+
if (!Object.hasOwn(variables, name)) {
|
|
60
60
|
if (options.missing === "preserve")
|
|
61
61
|
return match;
|
|
62
62
|
throw new Error(`Missing prompt template variable: ${name}`);
|
|
@@ -65,7 +65,6 @@ export function renderPromptTemplate(template, variables, options = {}) {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
export async function assembleProviderInput(options) {
|
|
68
|
-
const inputBuilder = options.inputBuilder ?? createDefaultInputBuilder();
|
|
69
68
|
const baseContext = {
|
|
70
69
|
sessionId: options.sessionId,
|
|
71
70
|
runId: options.runId,
|
|
@@ -76,6 +75,18 @@ export async function assembleProviderInput(options) {
|
|
|
76
75
|
// filter against loop-local turn. Instructions layer via composeSystemPrompt (no parallel prompt
|
|
77
76
|
// code); contextBlocks merge via resolveContextProviders (middleware still runs).
|
|
78
77
|
const turn = options.turn ?? 1;
|
|
78
|
+
const foldContext = {
|
|
79
|
+
sessionId: options.sessionId ?? "",
|
|
80
|
+
runId: options.runId ?? "",
|
|
81
|
+
turn,
|
|
82
|
+
signal: options.signal,
|
|
83
|
+
};
|
|
84
|
+
const foldedHistory = options.toolResultFold
|
|
85
|
+
? await foldToolResultHistory(options.history ?? [], options.toolResultFold, foldContext)
|
|
86
|
+
: (options.history ?? []);
|
|
87
|
+
const foldedToolResults = options.toolResultFold && options.toolResults?.length
|
|
88
|
+
? await foldToolResults(options.toolResults, options.toolResultFold, foldContext)
|
|
89
|
+
: options.toolResults;
|
|
79
90
|
const injectorContribs = options.instructionInjectors?.length
|
|
80
91
|
? runInstructionInjectors(options.instructionInjectors, {
|
|
81
92
|
sessionId: options.sessionId ?? "",
|
|
@@ -83,7 +94,7 @@ export async function assembleProviderInput(options) {
|
|
|
83
94
|
turn,
|
|
84
95
|
// Runtime history is already redacted; input is redacted here before injector code sees it.
|
|
85
96
|
input: inputMessages(options.input).map((message) => redactMessage(message, options.redactor)),
|
|
86
|
-
history:
|
|
97
|
+
history: foldedHistory,
|
|
87
98
|
metadata: options.metadata ?? {},
|
|
88
99
|
signal: options.signal ?? new AbortController().signal,
|
|
89
100
|
})
|
|
@@ -91,51 +102,136 @@ export async function assembleProviderInput(options) {
|
|
|
91
102
|
const systemInstructions = injectorContribs.instructions.length
|
|
92
103
|
? composeSystemPrompt(injectorContribs.instructions, { base: options.systemInstructions })
|
|
93
104
|
: options.systemInstructions;
|
|
94
|
-
const buildContext = {
|
|
95
|
-
|
|
96
|
-
const context = await resolveContextProviders({
|
|
97
|
-
providers: options.contextProviders,
|
|
98
|
-
messages,
|
|
99
|
-
injectedBlocks: injectorContribs.contextBlocks.length ? injectorContribs.contextBlocks : undefined,
|
|
100
|
-
middleware: options.middleware,
|
|
105
|
+
const buildContext = {
|
|
106
|
+
...options,
|
|
101
107
|
...baseContext,
|
|
102
|
-
|
|
108
|
+
systemInstructions,
|
|
109
|
+
history: foldedHistory,
|
|
110
|
+
toolResults: foldedToolResults,
|
|
111
|
+
};
|
|
112
|
+
const layout = buildContext.inputLayout ?? "cache_aware";
|
|
113
|
+
let messages;
|
|
114
|
+
let context;
|
|
115
|
+
let skills = options.skills;
|
|
116
|
+
let tools = options.tools;
|
|
117
|
+
let demotedSkillBodies;
|
|
118
|
+
let budgetReport;
|
|
119
|
+
if (options.contextBudget) {
|
|
120
|
+
// ponytail: budget path always uses default groups so eviction kinds stay deterministic;
|
|
121
|
+
// custom inputBuilder still honored when contextBudget is absent.
|
|
122
|
+
const groups = await buildDefaultInputMessageGroups(options.input, buildContext);
|
|
123
|
+
context = await resolveContextProviders({
|
|
124
|
+
providers: options.contextProviders,
|
|
125
|
+
messages: flattenInputGroups(groups, layout),
|
|
126
|
+
injectedBlocks: injectorContribs.contextBlocks.length ? injectorContribs.contextBlocks : undefined,
|
|
127
|
+
middleware: options.middleware,
|
|
128
|
+
...baseContext,
|
|
129
|
+
});
|
|
130
|
+
const applied = applyContextBudget({
|
|
131
|
+
groups,
|
|
132
|
+
context,
|
|
133
|
+
skills: skills ?? [],
|
|
134
|
+
tools,
|
|
135
|
+
budget: options.contextBudget,
|
|
136
|
+
layout,
|
|
137
|
+
skillsDisclosure: options.skillsDisclosure,
|
|
138
|
+
loadedSkills: options.loadedSkills,
|
|
139
|
+
});
|
|
140
|
+
messages = flattenInputGroups(applied.groups, layout);
|
|
141
|
+
if (buildContext.middleware)
|
|
142
|
+
messages = await buildContext.middleware.run("input_assembly", messages);
|
|
143
|
+
context = applied.context;
|
|
144
|
+
skills = applied.skills;
|
|
145
|
+
tools = applied.tools;
|
|
146
|
+
demotedSkillBodies = applied.demotedSkillBodies;
|
|
147
|
+
if (options.contextBudget.reportOmissions)
|
|
148
|
+
budgetReport = applied.report;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const inputBuilder = options.inputBuilder ?? createDefaultInputBuilder();
|
|
152
|
+
messages = await inputBuilder.build(options.input, buildContext);
|
|
153
|
+
// Runtime-owned: input_assembly middleware always runs, regardless of which builder is installed.
|
|
154
|
+
if (buildContext.middleware)
|
|
155
|
+
messages = await buildContext.middleware.run("input_assembly", messages);
|
|
156
|
+
context = await resolveContextProviders({
|
|
157
|
+
providers: options.contextProviders,
|
|
158
|
+
messages,
|
|
159
|
+
injectedBlocks: injectorContribs.contextBlocks.length ? injectorContribs.contextBlocks : undefined,
|
|
160
|
+
middleware: options.middleware,
|
|
161
|
+
...baseContext,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
103
164
|
const promptBuilder = options.promptBuilder ?? createDefaultPromptBuilder();
|
|
104
165
|
const promptRequest = options.middleware
|
|
105
166
|
? await options.middleware.run("prompt_build", {
|
|
106
167
|
messages,
|
|
107
168
|
context,
|
|
108
|
-
skills
|
|
109
|
-
|
|
169
|
+
skills,
|
|
170
|
+
skillsDisclosure: options.skillsDisclosure,
|
|
171
|
+
loadedSkills: options.loadedSkills,
|
|
172
|
+
demotedSkillBodies,
|
|
173
|
+
tools,
|
|
110
174
|
metadata: options.metadata,
|
|
111
175
|
signal: options.signal,
|
|
112
176
|
})
|
|
113
177
|
: {
|
|
114
178
|
messages,
|
|
115
179
|
context,
|
|
116
|
-
skills
|
|
117
|
-
|
|
180
|
+
skills,
|
|
181
|
+
skillsDisclosure: options.skillsDisclosure,
|
|
182
|
+
loadedSkills: options.loadedSkills,
|
|
183
|
+
demotedSkillBodies,
|
|
184
|
+
tools,
|
|
118
185
|
metadata: options.metadata,
|
|
119
186
|
signal: options.signal,
|
|
120
187
|
};
|
|
121
|
-
const providerMessages = await promptBuilder.build({ ...promptRequest, tools: options.
|
|
188
|
+
const providerMessages = await promptBuilder.build({ ...promptRequest, tools, model: options.model });
|
|
122
189
|
assertMessagesSupportModelCapabilities(options.model, providerMessages);
|
|
190
|
+
const metadata = budgetReport ? { ...options.metadata, [CONTEXT_BUDGET_REPORT_METADATA_KEY]: budgetReport } : options.metadata;
|
|
123
191
|
return {
|
|
124
192
|
model: options.model,
|
|
125
193
|
messages: providerMessages,
|
|
126
|
-
tools
|
|
194
|
+
tools,
|
|
127
195
|
context,
|
|
128
196
|
options: options.providerOptions,
|
|
129
|
-
metadata
|
|
197
|
+
metadata,
|
|
130
198
|
signal: options.signal,
|
|
131
199
|
};
|
|
132
200
|
}
|
|
201
|
+
async function buildDefaultInputMessageGroups(input, context) {
|
|
202
|
+
return {
|
|
203
|
+
instructions: [
|
|
204
|
+
...instructionMessages(context.systemInstructions, "System instruction"),
|
|
205
|
+
...instructionMessages(context.developerInstructions, "Developer instruction"),
|
|
206
|
+
...customInstructionMessages(context.instructions),
|
|
207
|
+
],
|
|
208
|
+
summaries: summaryMessages(context.summaries),
|
|
209
|
+
history: [...(context.history ?? [])],
|
|
210
|
+
input: inputMessages(input),
|
|
211
|
+
attachments: await attachmentMessages(context),
|
|
212
|
+
toolResults: toolResultMessages(context.toolResults),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
133
215
|
function flattenInputGroups(groups, layout) {
|
|
134
216
|
switch (layout) {
|
|
135
217
|
case "cache_aware":
|
|
136
|
-
return [
|
|
218
|
+
return [
|
|
219
|
+
...groups.instructions,
|
|
220
|
+
...groups.attachments,
|
|
221
|
+
...groups.summaries,
|
|
222
|
+
...groups.history,
|
|
223
|
+
...groups.toolResults,
|
|
224
|
+
...groups.input,
|
|
225
|
+
];
|
|
137
226
|
case "legacy":
|
|
138
|
-
return [
|
|
227
|
+
return [
|
|
228
|
+
...groups.instructions,
|
|
229
|
+
...groups.summaries,
|
|
230
|
+
...groups.history,
|
|
231
|
+
...groups.input,
|
|
232
|
+
...groups.attachments,
|
|
233
|
+
...groups.toolResults,
|
|
234
|
+
];
|
|
139
235
|
}
|
|
140
236
|
}
|
|
141
237
|
export function inputMessages(input) {
|
|
@@ -146,7 +242,7 @@ export function inputMessages(input) {
|
|
|
146
242
|
return [...input];
|
|
147
243
|
}
|
|
148
244
|
function instructionMessages(value, label) {
|
|
149
|
-
const items = typeof value === "string" ? [value] : value ?? [];
|
|
245
|
+
const items = typeof value === "string" ? [value] : (value ?? []);
|
|
150
246
|
return items.map((text) => textMessage("system", `${label}:\n${text}`));
|
|
151
247
|
}
|
|
152
248
|
function customInstructionMessages(value) {
|
|
@@ -198,13 +294,16 @@ async function resourceMessage(uri, context, attachment) {
|
|
|
198
294
|
function toolResultMessages(results) {
|
|
199
295
|
return (results ?? []).map((result) => ({
|
|
200
296
|
role: "tool",
|
|
201
|
-
content: [
|
|
297
|
+
content: [
|
|
298
|
+
{
|
|
202
299
|
type: "tool_result",
|
|
203
300
|
toolCallId: result.toolCallId,
|
|
204
301
|
name: result.name,
|
|
205
302
|
result: result.value,
|
|
206
303
|
error: result.error,
|
|
207
|
-
},
|
|
304
|
+
},
|
|
305
|
+
...(result.content ?? []),
|
|
306
|
+
],
|
|
208
307
|
metadata: result.metadata,
|
|
209
308
|
}));
|
|
210
309
|
}
|
|
@@ -214,20 +313,18 @@ function textMessage(role, text, metadata) {
|
|
|
214
313
|
function contextMessages(context) {
|
|
215
314
|
return (context ?? []).map((block) => textMessage("system", `${block.title ? `${block.title}:\n` : "Context:\n"}${blockText(block)}`, block.metadata));
|
|
216
315
|
}
|
|
217
|
-
function skillMessages(skills) {
|
|
218
|
-
return (skills ?? [])
|
|
219
|
-
.filter((skill) => skill.instructions)
|
|
220
|
-
.map((skill) => textMessage("system", `Skill ${skill.name}:\n${skill.instructions}`, skill.metadata));
|
|
221
|
-
}
|
|
222
316
|
function toolMessages(tools) {
|
|
223
317
|
if (!tools?.length)
|
|
224
318
|
return [];
|
|
225
|
-
return [
|
|
319
|
+
return [
|
|
320
|
+
textMessage("system", `Available tools:\n${tools.map((tool) => `- ${tool.name}${tool.description ? `: ${tool.description}` : ""}`).join("\n")}`),
|
|
321
|
+
];
|
|
226
322
|
}
|
|
227
323
|
function blockText(block) {
|
|
228
324
|
if (typeof block.content === "string")
|
|
229
325
|
return block.content;
|
|
230
|
-
return block.content
|
|
326
|
+
return block.content
|
|
327
|
+
.map((part) => {
|
|
231
328
|
if (part.type === "text" || part.type === "thinking")
|
|
232
329
|
return part.text;
|
|
233
330
|
if (part.type === "tool_result")
|
|
@@ -245,7 +342,8 @@ function blockText(block) {
|
|
|
245
342
|
if (part.type === "document")
|
|
246
343
|
return part.transcript ?? part.name ?? part.url ?? part.resourceUri ?? part.mediaType ?? "[document]";
|
|
247
344
|
return "[content]";
|
|
248
|
-
})
|
|
345
|
+
})
|
|
346
|
+
.join("\n");
|
|
249
347
|
}
|
|
250
348
|
function templateValue(value) {
|
|
251
349
|
if (typeof value === "string")
|
|
@@ -259,7 +357,9 @@ function sortJson(value) {
|
|
|
259
357
|
return value;
|
|
260
358
|
if (Array.isArray(value))
|
|
261
359
|
return value.map(sortJson);
|
|
262
|
-
return Object.fromEntries(Object.keys(value)
|
|
360
|
+
return Object.fromEntries(Object.keys(value)
|
|
361
|
+
.sort()
|
|
362
|
+
.map((key) => [key, sortJson(value[key])]));
|
|
263
363
|
}
|
|
264
364
|
function throwIfAborted(signal) {
|
|
265
365
|
if (signal?.aborted)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ContributionRegistry } from "./contributions.js";
|
|
2
1
|
import type { ContextBlock, InstructionContext, InstructionInjector, SystemPromptContribution } from "./contracts.js";
|
|
2
|
+
import type { ContributionRegistry } from "./contributions.js";
|
|
3
3
|
/** Run each selected injector against `ctx`, returning the matching contributions as
|
|
4
4
|
* `package`-source `SystemPromptContribution[]` (for `composeSystemPrompt`) and
|
|
5
5
|
* `ContextBlock[]` (for the context merge). Aborts on `ctx.signal`. Non-matching
|
package/dist/middleware.js
CHANGED
|
@@ -21,10 +21,13 @@ export function createMiddlewareRegistry(options = {}) {
|
|
|
21
21
|
},
|
|
22
22
|
async run(hook, value) {
|
|
23
23
|
let current = value;
|
|
24
|
-
for (const middleware of byHook.get(hook) ?? []) {
|
|
24
|
+
for (const [index, middleware] of (byHook.get(hook) ?? []).entries()) {
|
|
25
25
|
try {
|
|
26
26
|
let calledNext = false;
|
|
27
27
|
const next = async (nextValue) => {
|
|
28
|
+
// Double next() forks the chain value nondeterministically — always a bug.
|
|
29
|
+
if (calledNext)
|
|
30
|
+
throw new Error(`Middleware hook "${hook}" #${index}: next() called more than once`);
|
|
28
31
|
calledNext = true;
|
|
29
32
|
current = nextValue;
|
|
30
33
|
return current;
|
|
@@ -32,6 +35,11 @@ export function createMiddlewareRegistry(options = {}) {
|
|
|
32
35
|
const result = await middleware(current, next);
|
|
33
36
|
if (!calledNext)
|
|
34
37
|
current = result;
|
|
38
|
+
else if (result !== undefined && result !== current) {
|
|
39
|
+
// next(v) already committed the chain value; a conflicting return is silently
|
|
40
|
+
// discarded. Ambiguous rather than certainly-wrong, so diagnose, don't throw.
|
|
41
|
+
await options.onError?.(middlewareError(new Error(`Middleware hook "${hook}" #${index}: called next(value) and returned a different value; the next() value wins, the return is discarded`), hook, secrets));
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
catch (error) {
|
|
37
45
|
if (errorPolicy === "throw")
|
package/dist/models.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ import type { ModelConfig } from "./contracts.js";
|
|
|
2
2
|
import { type DuplicateRegistrationOptions } from "./registry-options.js";
|
|
3
3
|
export interface ModelRegistry {
|
|
4
4
|
register(model: ModelConfig): void;
|
|
5
|
+
/** Remove a model; returns false when it was not registered. */
|
|
6
|
+
unregister(provider: string, model: string): boolean;
|
|
5
7
|
get(provider: string, model: string): ModelConfig | undefined;
|
|
6
8
|
resolve(provider: string, model: string): ModelConfig;
|
|
7
9
|
list(): readonly ModelConfig[];
|
package/dist/models.js
CHANGED
|
@@ -8,6 +8,9 @@ export function createModelRegistry(models = [], options = {}) {
|
|
|
8
8
|
assertCanRegister(byId, id, "model", `${model.provider}/${model.model}`, options.duplicate);
|
|
9
9
|
byId.set(id, model);
|
|
10
10
|
},
|
|
11
|
+
unregister(provider, model) {
|
|
12
|
+
return byId.delete(key(provider, model));
|
|
13
|
+
},
|
|
11
14
|
get(provider, model) {
|
|
12
15
|
return byId.get(key(provider, model));
|
|
13
16
|
},
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
1
2
|
import { join } from "node:path";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
3
|
-
import { readdir, stat } from "node:fs/promises";
|
|
4
|
-
import { parseSkillFile, splitFrontmatter } from "../contribution-parsing.js";
|
|
5
3
|
import { resolveAgentDefinition } from "../agent-definitions.js";
|
|
4
|
+
import { parseSkillFile, splitFrontmatter } from "../contribution-parsing.js";
|
|
6
5
|
import { assertPermission, isTrusted } from "../security.js";
|
|
7
|
-
import { isPathInsideReal } from "./trust.js";
|
|
8
|
-
import { readOptionalFile } from "./contribution-discovery.js";
|
|
9
6
|
import { createSkillRegistry } from "../skills.js";
|
|
10
7
|
import { isNodeErrorCode } from "./config.js";
|
|
8
|
+
import { readOptionalFile } from "./contribution-discovery.js";
|
|
9
|
+
import { isPathInsideReal } from "./trust.js";
|
|
11
10
|
const defaultInclude = {
|
|
12
11
|
systemPrompt: true,
|
|
13
12
|
agentPrompt: true,
|
|
@@ -288,7 +287,13 @@ function resolveSkillContexts(skills, contextProviders) {
|
|
|
288
287
|
function collectMetadata(front) {
|
|
289
288
|
const metadata = {};
|
|
290
289
|
for (const [key, value] of front) {
|
|
291
|
-
if (key !== "name" &&
|
|
290
|
+
if (key !== "name" &&
|
|
291
|
+
key !== "description" &&
|
|
292
|
+
key !== "model" &&
|
|
293
|
+
key !== "tools" &&
|
|
294
|
+
key !== "skills" &&
|
|
295
|
+
key !== "context" &&
|
|
296
|
+
key !== "instructions") {
|
|
292
297
|
metadata[key] = value;
|
|
293
298
|
}
|
|
294
299
|
}
|
|
@@ -305,7 +310,10 @@ function getStringList(front, key) {
|
|
|
305
310
|
if (Array.isArray(value))
|
|
306
311
|
return value.map(String);
|
|
307
312
|
if (typeof value === "string")
|
|
308
|
-
return value
|
|
313
|
+
return value
|
|
314
|
+
.split(",")
|
|
315
|
+
.map((s) => s.trim())
|
|
316
|
+
.filter(Boolean);
|
|
309
317
|
return undefined;
|
|
310
318
|
}
|
|
311
319
|
function bodyAsInstructions(text, path) {
|
|
@@ -348,7 +356,7 @@ async function readOptional(read, path) {
|
|
|
348
356
|
const NAME_RE = /^[A-Za-z0-9 _-]+$/;
|
|
349
357
|
function parentDirName(path) {
|
|
350
358
|
const parts = path.split(/[/\\]+/).filter(Boolean);
|
|
351
|
-
return parts.length >= 2 ? parts[parts.length - 2] : parts[parts.length - 1] ?? "";
|
|
359
|
+
return parts.length >= 2 ? parts[parts.length - 2] : (parts[parts.length - 1] ?? "");
|
|
352
360
|
}
|
|
353
361
|
/** Parse a `CONTEXT.md` into a static {@link ContextProvider}. The markdown
|
|
354
362
|
* body becomes the context block content; frontmatter `name` overrides the
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ContributionFileKind, DiscoveredContribution } from "../contracts.js";
|
|
2
|
-
import type { PermissionPolicy } from "../security.js";
|
|
3
|
-
import type { TrustPolicy } from "../security.js";
|
|
2
|
+
import type { PermissionPolicy, TrustPolicy } from "../security.js";
|
|
4
3
|
export interface DiscoveryOptions {
|
|
5
4
|
readonly kinds: readonly ContributionFileKind[];
|
|
6
5
|
/** Workspace root. Scans `<root>/.agents/<kind>s/<name>/`. Gated by `trust`. */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { isJsonObject } from "../config.js";
|
|
4
|
-
import { assertPermission } from "../security.js";
|
|
5
|
-
import { isPathInsideReal } from "./trust.js";
|
|
6
4
|
import { parseSkillFile } from "../contribution-parsing.js";
|
|
5
|
+
import { assertPermission } from "../security.js";
|
|
7
6
|
import { isNodeErrorCode } from "./config.js";
|
|
7
|
+
import { isPathInsideReal } from "./trust.js";
|
|
8
8
|
/**
|
|
9
9
|
* Discover contributions on disk. Scans the workspace `.agents/` tree only;
|
|
10
10
|
* no global root. One `readdir` per kind-root; no `import()`. Inert output —
|
|
@@ -72,7 +72,7 @@ async function readEntry(dir, fallbackName, kind, origin) {
|
|
|
72
72
|
return readManifestEntry(dir, fallbackName, kind, origin);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
|
-
async function readSkillEntry(dir,
|
|
75
|
+
async function readSkillEntry(dir, _fallbackName, origin) {
|
|
76
76
|
const path = join(dir, "SKILL.md");
|
|
77
77
|
if (!(await isPathInsideReal(dir, path)))
|
|
78
78
|
return undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { mkdir, readFile
|
|
1
|
+
import { appendFile, mkdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { SESSION_APPEND_CONFLICT_CODE, SessionAppendConflictError,
|
|
3
|
+
import { isSessionEntryKind, SESSION_APPEND_CONFLICT_CODE, SESSION_ENTRY_SCHEMA_VERSION, SessionAppendConflictError, SessionSearchUnsupportedError, } from "../contracts.js";
|
|
4
4
|
import { isNodeErrorCode } from "./config.js";
|
|
5
5
|
export function createJsonlSessionStore(pathOrOptions) {
|
|
6
6
|
const options = typeof pathOrOptions === "string" ? { path: pathOrOptions, createDirectory: true } : pathOrOptions;
|
|
@@ -46,6 +46,9 @@ export function createJsonlSessionStore(pathOrOptions) {
|
|
|
46
46
|
async get(id) {
|
|
47
47
|
return findEntry(path, id);
|
|
48
48
|
},
|
|
49
|
+
async searchSessions() {
|
|
50
|
+
throw new SessionSearchUnsupportedError("JSONL session store does not support searchSessions");
|
|
51
|
+
},
|
|
49
52
|
};
|
|
50
53
|
}
|
|
51
54
|
/** Read a JSONL session file and return both valid entries and per-line parse errors. */
|
|
@@ -90,7 +93,10 @@ function parseEntry(line, lineNumber) {
|
|
|
90
93
|
}
|
|
91
94
|
function validateSessionEntry(value, lineNumber, raw) {
|
|
92
95
|
if (!isBasicSessionEntry(value)) {
|
|
93
|
-
return {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: { line: lineNumber, message: "Invalid session entry: expected object with id, sessionId, timestamp, and kind", raw },
|
|
99
|
+
};
|
|
94
100
|
}
|
|
95
101
|
const entry = value;
|
|
96
102
|
if (entry.parentId !== undefined && typeof entry.parentId !== "string") {
|
|
@@ -146,10 +152,10 @@ function isBasicSessionEntry(value) {
|
|
|
146
152
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
147
153
|
return false;
|
|
148
154
|
const entry = value;
|
|
149
|
-
return typeof entry.id === "string"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
155
|
+
return (typeof entry.id === "string" &&
|
|
156
|
+
typeof entry.sessionId === "string" &&
|
|
157
|
+
typeof entry.timestamp === "string" &&
|
|
158
|
+
typeof entry.kind === "string");
|
|
153
159
|
}
|
|
154
160
|
function isMessage(value) {
|
|
155
161
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
package/dist/node/settings.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ConfigLayer } from "../config.js";
|
|
2
|
-
import { type NodeConfigFile } from "./config.js";
|
|
3
2
|
import type { SettingsProvider } from "../contracts.js";
|
|
3
|
+
import { type NodeConfigFile } from "./config.js";
|
|
4
4
|
export type NodeSettingsFile = NodeConfigFile;
|
|
5
5
|
export declare function defaultUserSettingsPath(appName?: string): string;
|
|
6
6
|
export declare function readSettingsFile(path: string): Promise<ConfigLayer["config"]>;
|
package/dist/node/settings.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { mergeConfigLayers } from "../config.js";
|
|
4
|
-
import { readConfigFile, isNodeErrorCode } from "./config.js";
|
|
5
4
|
import { createStaticSettingsProvider } from "../settings.js";
|
|
5
|
+
import { isNodeErrorCode, readConfigFile } from "./config.js";
|
|
6
6
|
export function defaultUserSettingsPath(appName = "prism") {
|
|
7
7
|
return join(homedir(), ".config", appName, "settings.json");
|
|
8
8
|
}
|
|
@@ -14,10 +14,8 @@ import { readOptionalFile } from "./contribution-discovery.js";
|
|
|
14
14
|
* singletons don't fit `discoverContributions`' named-subdir scanner, so this is a
|
|
15
15
|
* sibling loader mirroring `src/node/instruction-injectors.ts`'s per-concern adapter shape. */
|
|
16
16
|
export async function loadSystemPromptFiles(options) {
|
|
17
|
-
const agentsPath = options.agentsMdPath
|
|
18
|
-
|
|
19
|
-
const systemPath = options.systemMdPath
|
|
20
|
-
?? (options.globalRoot !== undefined ? join(options.globalRoot, ".prism", "agent", "SYSTEM.md") : undefined);
|
|
17
|
+
const agentsPath = options.agentsMdPath ?? (options.workspaceRoot !== undefined ? join(options.workspaceRoot, "AGENTS.md") : undefined);
|
|
18
|
+
const systemPath = options.systemMdPath ?? (options.globalRoot !== undefined ? join(options.globalRoot, ".prism", "agent", "SYSTEM.md") : undefined);
|
|
21
19
|
const out = [];
|
|
22
20
|
if (systemPath !== undefined) {
|
|
23
21
|
const layer = await readSystemFile(systemPath, options.permission);
|
package/dist/node/trust.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isAbsolute, relative, resolve, dirname, basename, join } from "node:path";
|
|
2
1
|
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
3
|
import { isNodeErrorCode } from "./config.js";
|
|
4
4
|
export function isPathInside(root, target) {
|
|
5
5
|
const from = resolve(root);
|