@lensagent/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/config/lens.example.jsonc +92 -0
- package/config/pair.example.json +3 -0
- package/dist/adapters/executor.d.ts +35 -0
- package/dist/adapters/executor.js +296 -0
- package/dist/adapters/lsp.d.ts +18 -0
- package/dist/adapters/lsp.js +218 -0
- package/dist/adapters/mcp.d.ts +32 -0
- package/dist/adapters/mcp.js +283 -0
- package/dist/adapters/revert.d.ts +12 -0
- package/dist/adapters/revert.js +155 -0
- package/dist/config/runtime.d.ts +55 -0
- package/dist/config/runtime.js +371 -0
- package/dist/config/schema.d.ts +292 -0
- package/dist/config/schema.js +177 -0
- package/dist/contracts/adapter.d.ts +28 -0
- package/dist/contracts/adapter.js +8 -0
- package/dist/contracts/capability.d.ts +41 -0
- package/dist/contracts/capability.js +1 -0
- package/dist/contracts/domain.d.ts +61 -0
- package/dist/contracts/domain.js +1 -0
- package/dist/contracts/index.d.ts +5 -0
- package/dist/contracts/index.js +5 -0
- package/dist/contracts/model.d.ts +77 -0
- package/dist/contracts/model.js +1 -0
- package/dist/contracts/ports.d.ts +14 -0
- package/dist/contracts/ports.js +14 -0
- package/dist/core/access.d.ts +24 -0
- package/dist/core/access.js +205 -0
- package/dist/core/codec.d.ts +33 -0
- package/dist/core/codec.js +105 -0
- package/dist/core/domain.d.ts +13 -0
- package/dist/core/domain.js +24 -0
- package/dist/core/host.d.ts +19 -0
- package/dist/core/host.js +249 -0
- package/dist/core/identity.d.ts +19 -0
- package/dist/core/identity.js +54 -0
- package/dist/entry/bun.d.ts +1 -0
- package/dist/entry/bun.js +2 -0
- package/dist/entry/node.d.ts +2 -0
- package/dist/entry/node.js +3 -0
- package/dist/entry/rebuild.d.ts +1 -0
- package/dist/entry/rebuild.js +47 -0
- package/dist/entry/run.d.ts +1 -0
- package/dist/entry/run.js +43 -0
- package/dist/execution/lsp-process.d.ts +14 -0
- package/dist/execution/lsp-process.js +234 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +1332 -0
- package/dist/launch.d.ts +3 -0
- package/dist/launch.js +4 -0
- package/dist/runtime/agent.d.ts +35 -0
- package/dist/runtime/agent.js +853 -0
- package/dist/runtime/artifacts.d.ts +15 -0
- package/dist/runtime/artifacts.js +72 -0
- package/dist/runtime/cache.d.ts +20 -0
- package/dist/runtime/cache.js +44 -0
- package/dist/runtime/calls.d.ts +21 -0
- package/dist/runtime/calls.js +130 -0
- package/dist/runtime/capabilities.d.ts +58 -0
- package/dist/runtime/capabilities.js +196 -0
- package/dist/runtime/cleanup.d.ts +7 -0
- package/dist/runtime/cleanup.js +33 -0
- package/dist/runtime/context.d.ts +34 -0
- package/dist/runtime/context.js +169 -0
- package/dist/runtime/diagnostics.d.ts +8 -0
- package/dist/runtime/diagnostics.js +71 -0
- package/dist/runtime/events.d.ts +22 -0
- package/dist/runtime/events.js +131 -0
- package/dist/runtime/kernel-capabilities.d.ts +32 -0
- package/dist/runtime/kernel-capabilities.js +200 -0
- package/dist/runtime/manifests.d.ts +14 -0
- package/dist/runtime/manifests.js +117 -0
- package/dist/runtime/model.d.ts +20 -0
- package/dist/runtime/model.js +241 -0
- package/dist/runtime/observability.d.ts +22 -0
- package/dist/runtime/observability.js +104 -0
- package/dist/runtime/policy.d.ts +8 -0
- package/dist/runtime/policy.js +31 -0
- package/dist/runtime/profile.d.ts +8 -0
- package/dist/runtime/profile.js +52 -0
- package/dist/runtime/projects.d.ts +40 -0
- package/dist/runtime/projects.js +115 -0
- package/dist/runtime/results.d.ts +7 -0
- package/dist/runtime/results.js +55 -0
- package/dist/runtime/review.d.ts +9 -0
- package/dist/runtime/review.js +54 -0
- package/dist/runtime/scheduler.d.ts +15 -0
- package/dist/runtime/scheduler.js +85 -0
- package/dist/runtime/skills.d.ts +2 -0
- package/dist/runtime/skills.js +83 -0
- package/dist/runtime/tokenizer.d.ts +8 -0
- package/dist/runtime/tokenizer.js +30 -0
- package/dist/store/database.d.ts +3 -0
- package/dist/store/database.js +49 -0
- package/dist/store/event-log.d.ts +19 -0
- package/dist/store/event-log.js +61 -0
- package/dist/store/schema.d.ts +1 -0
- package/dist/store/schema.js +347 -0
- package/dist/store/store.d.ts +344 -0
- package/dist/store/store.js +2554 -0
- package/package.json +73 -0
- package/proto/executor.proto +314 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { digest, toolArguments } from '../core/codec.js';
|
|
2
|
+
import { fail } from '../core/domain.js';
|
|
3
|
+
import { estimateRequest, estimateTokens } from './tokenizer.js';
|
|
4
|
+
export class ContextEngine {
|
|
5
|
+
store;
|
|
6
|
+
registry;
|
|
7
|
+
constructor(store, registry) {
|
|
8
|
+
this.store = store;
|
|
9
|
+
this.registry = registry;
|
|
10
|
+
}
|
|
11
|
+
capture(projectId, agentId) {
|
|
12
|
+
return this.store.contextSource(projectId, agentId);
|
|
13
|
+
}
|
|
14
|
+
prepare(projectId, agentId, config, contextWindowTokens, profile, requestFrame) {
|
|
15
|
+
return this.prepareSource(this.capture(projectId, agentId), config, contextWindowTokens, profile, requestFrame);
|
|
16
|
+
}
|
|
17
|
+
prepareSource(source, config, contextWindowTokens, profile, requestFrame) {
|
|
18
|
+
const agentId = string(source.agent.id, 'agent_id');
|
|
19
|
+
const sourceRevision = number(source.agent.context_revision, 'context_revision');
|
|
20
|
+
const overrides = new Map(source.overrides.map((entry) => [`${string(entry.target_kind)}:${string(entry.target_id)}`, string(entry.instructions)]));
|
|
21
|
+
const visibleItems = source.items.filter((item) => item.visible === true);
|
|
22
|
+
const latestCompaction = visibleItems.findLast((item) => item.kind === 'compaction');
|
|
23
|
+
const workItems = latestCompaction === undefined
|
|
24
|
+
? visibleItems
|
|
25
|
+
: [latestCompaction, ...visibleItems.filter((item) => item.id !== latestCompaction.id && item.locked !== true)];
|
|
26
|
+
let messages = workItems.map((item) => {
|
|
27
|
+
const role = roleOf(item.role);
|
|
28
|
+
const content = string(item.content);
|
|
29
|
+
if (item.kind === 'tool_calls') {
|
|
30
|
+
const calls = JSON.parse(content);
|
|
31
|
+
if (!Array.isArray(calls))
|
|
32
|
+
fail('DATABASE_CORRUPT', 503, 'A persisted Tool Call block is invalid.');
|
|
33
|
+
return {
|
|
34
|
+
role: 'assistant',
|
|
35
|
+
content: '',
|
|
36
|
+
toolCalls: calls.map((entry) => {
|
|
37
|
+
if (typeof entry !== 'object' || entry === null || Array.isArray(entry))
|
|
38
|
+
fail('DATABASE_CORRUPT', 503, 'A persisted Tool Call is invalid.');
|
|
39
|
+
const value = entry;
|
|
40
|
+
// Normalised on the way out as well as on the way in, so a Context already holding a string
|
|
41
|
+
// from before the capture was fixed becomes replayable instead of staying permanently dead.
|
|
42
|
+
return { id: stringValue(value.id), name: stringValue(value.name), arguments: toolArguments(value.arguments) };
|
|
43
|
+
})
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const override = overrides.get(`${string(item.kind)}:${string(item.source_id)}`);
|
|
47
|
+
const base = { role, content: override === undefined ? content : `${override}\n\n${content}` };
|
|
48
|
+
const toolCallId = optionalString(item.tool_call_id);
|
|
49
|
+
const toolName = optionalString(item.tool_name);
|
|
50
|
+
if (role === 'tool' && (toolCallId === undefined || toolName === undefined)) {
|
|
51
|
+
return { role: 'user', content: `Included Result:\n${base.content}` };
|
|
52
|
+
}
|
|
53
|
+
return role === 'tool'
|
|
54
|
+
? { ...base, ...(toolCallId === undefined ? {} : { toolCallId }), ...(toolName === undefined ? {} : { toolName }) }
|
|
55
|
+
: base;
|
|
56
|
+
});
|
|
57
|
+
const agentOverride = overrides.get(`agent:${agentId}`);
|
|
58
|
+
if (agentOverride !== undefined)
|
|
59
|
+
messages = [{ role: 'system', content: agentOverride }, ...messages];
|
|
60
|
+
const skillPrompts = source.capabilities
|
|
61
|
+
.filter((entry) => entry.loaded === true)
|
|
62
|
+
.flatMap((entry) => {
|
|
63
|
+
const capabilityId = string(entry.capability_id);
|
|
64
|
+
const definition = this.registry.find(capabilityId);
|
|
65
|
+
if (definition === undefined)
|
|
66
|
+
return [];
|
|
67
|
+
return definition.kind === 'skill' && definition.promptText !== undefined ? [definition.promptText] : [];
|
|
68
|
+
});
|
|
69
|
+
if (skillPrompts.length > 0)
|
|
70
|
+
messages = [{ role: 'system', content: skillPrompts.join('\n\n') }, ...messages];
|
|
71
|
+
messages = [{ role: 'system', content: profile.value.systemPrompt.content }, ...messages];
|
|
72
|
+
const reserve = config.contextBudget?.outputReserveTokens ?? 4096;
|
|
73
|
+
const margin = config.contextBudget?.safetyMarginTokens ?? 1024;
|
|
74
|
+
const maximum = contextWindowTokens - reserve - margin;
|
|
75
|
+
if (maximum < 1)
|
|
76
|
+
fail('CONTEXT_BUDGET_INVALID', 503, 'The configured context budget leaves no model input capacity.');
|
|
77
|
+
const decisions = [];
|
|
78
|
+
let estimate = estimateMessages(messages, requestFrame);
|
|
79
|
+
const projection = config.contextProjection;
|
|
80
|
+
if (estimate.safe > maximum && projection?.toolResultMaxTokens !== undefined) {
|
|
81
|
+
const sourceTokens = estimate.safe;
|
|
82
|
+
messages = toolResultBudget(messages, projection.toolResultMaxTokens);
|
|
83
|
+
estimate = estimateMessages(messages, requestFrame);
|
|
84
|
+
decisions.push({ stage: 'tool_result_budget', sourceTokens, projectedTokens: estimate.safe });
|
|
85
|
+
}
|
|
86
|
+
if (estimate.safe > maximum && projection?.snip !== undefined && estimate.safe > projection.snip.triggerTokens && messages.length > 4) {
|
|
87
|
+
const sourceTokens = estimate.safe;
|
|
88
|
+
const retainedBytes = Math.max(1, Math.floor(projection.snip.retainedTokens * 3 / Math.max(1, messages.length - 3)));
|
|
89
|
+
messages = messages.map((entry, index) => index > 0 && index < messages.length - 2 ? { ...entry, content: snip(entry.content, retainedBytes) } : entry);
|
|
90
|
+
estimate = estimateMessages(messages, requestFrame);
|
|
91
|
+
decisions.push({ stage: 'snip', sourceTokens, projectedTokens: estimate.safe });
|
|
92
|
+
}
|
|
93
|
+
if (estimate.safe > maximum && projection?.microcompact !== undefined && estimate.safe > projection.microcompact.triggerTokens && messages.length > 6) {
|
|
94
|
+
const sourceTokens = estimate.safe;
|
|
95
|
+
const head = first(messages);
|
|
96
|
+
const tail = messages.slice(-4);
|
|
97
|
+
messages = [head, { role: 'system', content: snip(localSummary(messages.slice(1, -4)), projection.microcompact.projectedTokens * 3) }, ...tail];
|
|
98
|
+
estimate = estimateMessages(messages, requestFrame);
|
|
99
|
+
decisions.push({ stage: 'microcompact', sourceTokens, projectedTokens: estimate.safe });
|
|
100
|
+
}
|
|
101
|
+
if (estimate.safe > maximum && projection?.contextCollapse !== undefined && estimate.safe > projection.contextCollapse.triggerTokens && messages.length > 2) {
|
|
102
|
+
const sourceTokens = estimate.safe;
|
|
103
|
+
const target = Math.min(maximum, projection.contextCollapse.projectedTokens);
|
|
104
|
+
while (messages.length > 2 && estimate.safe > target) {
|
|
105
|
+
messages = [first(messages), ...messages.slice(2)];
|
|
106
|
+
estimate = estimateMessages(messages, requestFrame);
|
|
107
|
+
}
|
|
108
|
+
decisions.push({ stage: 'context_collapse', sourceTokens, projectedTokens: estimate.safe });
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
source,
|
|
112
|
+
messages,
|
|
113
|
+
estimate,
|
|
114
|
+
sourceRevision,
|
|
115
|
+
digest: digest(messages),
|
|
116
|
+
decisions
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function estimateMessages(messages, requestFrame) {
|
|
121
|
+
return requestFrame === undefined
|
|
122
|
+
? estimateTokens(messages.map((entry) => `${entry.role}\n${entry.content}`).join('\n'))
|
|
123
|
+
: estimateRequest({ messages, ...requestFrame });
|
|
124
|
+
}
|
|
125
|
+
function toolResultBudget(messages, maximumTokens) {
|
|
126
|
+
const maximumBytes = maximumTokens * 3;
|
|
127
|
+
return messages.map((entry) => entry.role === 'tool' && Buffer.byteLength(entry.content) > maximumBytes
|
|
128
|
+
? { ...entry, content: `${Buffer.from(entry.content).subarray(0, maximumBytes).toString()}\n[tool result truncated]` }
|
|
129
|
+
: entry);
|
|
130
|
+
}
|
|
131
|
+
function snip(value, maximumBytes) {
|
|
132
|
+
if (Buffer.byteLength(value) <= maximumBytes)
|
|
133
|
+
return value;
|
|
134
|
+
const half = Math.floor(maximumBytes / 2);
|
|
135
|
+
const bytes = Buffer.from(value);
|
|
136
|
+
return `${bytes.subarray(0, half).toString()}\n[snip]\n${bytes.subarray(bytes.length - half).toString()}`;
|
|
137
|
+
}
|
|
138
|
+
function localSummary(messages) {
|
|
139
|
+
return `Earlier context (${messages.length} messages):\n${messages.map((entry) => `- ${entry.role}: ${snip(entry.content.replaceAll('\n', ' '), 256)}`).join('\n')}`;
|
|
140
|
+
}
|
|
141
|
+
function roleOf(value) {
|
|
142
|
+
if (value === 'system' || value === 'user' || value === 'assistant' || value === 'tool')
|
|
143
|
+
return value;
|
|
144
|
+
return 'user';
|
|
145
|
+
}
|
|
146
|
+
function string(value, field = 'value') {
|
|
147
|
+
if (typeof value !== 'string')
|
|
148
|
+
fail('DATABASE_CORRUPT', 503, `${field} is not a string.`);
|
|
149
|
+
return value;
|
|
150
|
+
}
|
|
151
|
+
function number(value, field) {
|
|
152
|
+
if (typeof value !== 'number')
|
|
153
|
+
fail('DATABASE_CORRUPT', 503, `${field} is not a number.`);
|
|
154
|
+
return value;
|
|
155
|
+
}
|
|
156
|
+
function optionalString(value) {
|
|
157
|
+
return typeof value === 'string' ? value : undefined;
|
|
158
|
+
}
|
|
159
|
+
function first(messages) {
|
|
160
|
+
const message = messages[0];
|
|
161
|
+
if (message === undefined)
|
|
162
|
+
fail('CONTEXT_EMPTY', 503, 'Prepared Context is empty.');
|
|
163
|
+
return message;
|
|
164
|
+
}
|
|
165
|
+
function stringValue(value) {
|
|
166
|
+
if (typeof value !== 'string')
|
|
167
|
+
fail('DATABASE_CORRUPT', 503, 'A persisted Tool Call field is invalid.');
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Json } from '../core/domain.js';
|
|
2
|
+
import type { HarnessConfig } from '../config/schema.js';
|
|
3
|
+
import type { ContextSource } from './context.js';
|
|
4
|
+
export interface PreparationDiagnostics {
|
|
5
|
+
readonly agentIr: Json;
|
|
6
|
+
readonly executive: Json;
|
|
7
|
+
}
|
|
8
|
+
export declare function derivePreparationDiagnostics(source: ContextSource, config: HarnessConfig): PreparationDiagnostics;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { digest } from '../core/codec.js';
|
|
2
|
+
export function derivePreparationDiagnostics(source, config) {
|
|
3
|
+
const units = source.items.map((item, index) => unit(item, index + 1));
|
|
4
|
+
const agentIrDigest = digest({ version: 'agent-ir-v1', units });
|
|
5
|
+
const intents = units.filter((entry) => entry.kind === 'UserIntent');
|
|
6
|
+
const evidence = units.filter((entry) => entry.kind === 'ToolReceipt' || entry.kind === 'Failure');
|
|
7
|
+
const checkpoint = [...units].reverse().find((entry) => entry.kind === 'Checkpoint');
|
|
8
|
+
const verification = config.executive.verification.map((entry) => ({
|
|
9
|
+
id: entry.id,
|
|
10
|
+
description: entry.description,
|
|
11
|
+
source_digest: digest({ version: 'executive-verification-v1', id: entry.id, description: entry.description })
|
|
12
|
+
}));
|
|
13
|
+
const evidenceDigest = digest({
|
|
14
|
+
version: 'executive-evidence-v1',
|
|
15
|
+
evidence: evidence.map((entry) => typeof entry.digest === 'string' ? entry.digest : '')
|
|
16
|
+
});
|
|
17
|
+
const executive = {
|
|
18
|
+
version: 'executive-snapshot-v1',
|
|
19
|
+
intent_count: intents.length,
|
|
20
|
+
verification,
|
|
21
|
+
evidence_count: evidence.length,
|
|
22
|
+
evidence_set_digest: evidenceDigest,
|
|
23
|
+
checkpoint_digest: checkpoint?.digest ?? null,
|
|
24
|
+
completion_gate_status: verification.length === 0 ? 'not_configured' : 'pending_explicit_verification'
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
agentIr: {
|
|
28
|
+
compiler_id: 'core.agent-ir',
|
|
29
|
+
compiler_version: '1',
|
|
30
|
+
unit_count: units.length,
|
|
31
|
+
digest: agentIrDigest
|
|
32
|
+
},
|
|
33
|
+
executive: { ...executive, digest: digest(executive) }
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function unit(item, ordinal) {
|
|
37
|
+
const role = string(item.role);
|
|
38
|
+
const itemKind = string(item.kind);
|
|
39
|
+
const kind = itemKind === 'compaction' ? 'Checkpoint'
|
|
40
|
+
: itemKind === 'tool_calls' ? 'ToolInvocation'
|
|
41
|
+
: itemKind === 'result' ? resultKind(item)
|
|
42
|
+
: role === 'user' ? 'UserIntent'
|
|
43
|
+
: role === 'system' ? 'TaskConstraint'
|
|
44
|
+
: 'Observation';
|
|
45
|
+
const source = {
|
|
46
|
+
id: string(item.source_id),
|
|
47
|
+
version: number(item.revision),
|
|
48
|
+
digest: digest({
|
|
49
|
+
source_id: string(item.source_id),
|
|
50
|
+
revision: number(item.revision),
|
|
51
|
+
content: string(item.content)
|
|
52
|
+
})
|
|
53
|
+
};
|
|
54
|
+
const base = { ordinal, kind, role, source };
|
|
55
|
+
return { ...base, digest: digest(base) };
|
|
56
|
+
}
|
|
57
|
+
function resultKind(item) {
|
|
58
|
+
try {
|
|
59
|
+
const value = JSON.parse(string(item.content));
|
|
60
|
+
return value.error_code === null || value.error_code === undefined ? 'ToolReceipt' : 'Failure';
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return 'ToolReceipt';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function string(value) {
|
|
67
|
+
return typeof value === 'string' ? value : '';
|
|
68
|
+
}
|
|
69
|
+
function number(value) {
|
|
70
|
+
return typeof value === 'number' ? value : 0;
|
|
71
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ChangeSet, Json, RuntimeEvent } from '../core/domain.js';
|
|
2
|
+
export interface EventLimits {
|
|
3
|
+
readonly maxBufferedEvents: number;
|
|
4
|
+
readonly maxBufferedBytes: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Subscription {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
next(signal: AbortSignal): Promise<RuntimeEvent | null>;
|
|
9
|
+
close(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare class EventBus {
|
|
12
|
+
#private;
|
|
13
|
+
readonly instanceEpoch: string;
|
|
14
|
+
readonly metadataRevision: () => number;
|
|
15
|
+
constructor(instanceEpoch: string, limits: EventLimits, metadataRevision: () => number);
|
|
16
|
+
updateLimits(limits: EventLimits): void;
|
|
17
|
+
publish(change: ChangeSet): void;
|
|
18
|
+
emit(projectId: string, stateRevision: number, type: RuntimeEvent['type'], payload: Json): void;
|
|
19
|
+
subscribe(clientId: string, projectId: string): Subscription;
|
|
20
|
+
revoke(clientId: string): void;
|
|
21
|
+
close(): void;
|
|
22
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { id, now } from '../core/codec.js';
|
|
3
|
+
export class EventBus {
|
|
4
|
+
instanceEpoch;
|
|
5
|
+
metadataRevision;
|
|
6
|
+
#subscribers = new Map();
|
|
7
|
+
#lifecycle = new EventEmitter();
|
|
8
|
+
#limits;
|
|
9
|
+
constructor(instanceEpoch, limits, metadataRevision) {
|
|
10
|
+
this.instanceEpoch = instanceEpoch;
|
|
11
|
+
this.metadataRevision = metadataRevision;
|
|
12
|
+
this.#limits = limits;
|
|
13
|
+
}
|
|
14
|
+
updateLimits(limits) {
|
|
15
|
+
this.#limits = limits;
|
|
16
|
+
}
|
|
17
|
+
publish(change) {
|
|
18
|
+
// Drops the two internal aliases and forwards the rest of `ChangedEntityRef` whole. Listing the
|
|
19
|
+
// fields to keep is what broke this twice: first it reprojected each entry down to `{ type, id }`
|
|
20
|
+
// and discarded the `read_route` a subscriber needs, then the replacement enumerated six fields
|
|
21
|
+
// and silently dropped the 07 §4.2 invalidation scope that was added later. A subscriber cannot
|
|
22
|
+
// tell a field that was never derived from one that was derived and then omitted here, so the
|
|
23
|
+
// omission is structural: only `type` and `id` are named, and they are the only ones internal.
|
|
24
|
+
this.emit(change.projectId, change.stateRevision, 'entity.changed', {
|
|
25
|
+
changes: change.changes.map((entry) => wireChange(entry))
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
emit(projectId, stateRevision, type, payload) {
|
|
29
|
+
const event = {
|
|
30
|
+
id: id('event'),
|
|
31
|
+
projectId,
|
|
32
|
+
stateRevision,
|
|
33
|
+
metadataRevision: this.metadataRevision(),
|
|
34
|
+
type,
|
|
35
|
+
payload,
|
|
36
|
+
occurredAt: now()
|
|
37
|
+
};
|
|
38
|
+
for (const subscriber of this.#subscribers.values()) {
|
|
39
|
+
if (subscriber.projectId === projectId && !subscriber.closed)
|
|
40
|
+
this.#enqueue(subscriber, event);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
subscribe(clientId, projectId) {
|
|
44
|
+
const subscriber = {
|
|
45
|
+
id: id('subscription'),
|
|
46
|
+
clientId,
|
|
47
|
+
projectId,
|
|
48
|
+
queue: [],
|
|
49
|
+
bytes: 0,
|
|
50
|
+
wake: undefined,
|
|
51
|
+
closeAfterDrain: false,
|
|
52
|
+
closed: false
|
|
53
|
+
};
|
|
54
|
+
this.#subscribers.set(subscriber.id, subscriber);
|
|
55
|
+
this.#lifecycle.emit('subscribed', subscriber.id);
|
|
56
|
+
return {
|
|
57
|
+
id: subscriber.id,
|
|
58
|
+
next: (signal) => this.#next(subscriber, signal),
|
|
59
|
+
close: () => this.#close(subscriber)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
revoke(clientId) {
|
|
63
|
+
for (const subscriber of this.#subscribers.values()) {
|
|
64
|
+
if (subscriber.clientId === clientId)
|
|
65
|
+
this.#close(subscriber);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
close() {
|
|
69
|
+
for (const subscriber of this.#subscribers.values())
|
|
70
|
+
this.#close(subscriber);
|
|
71
|
+
this.#lifecycle.removeAllListeners();
|
|
72
|
+
}
|
|
73
|
+
async #next(subscriber, signal) {
|
|
74
|
+
while (!subscriber.closed) {
|
|
75
|
+
const event = subscriber.queue.shift();
|
|
76
|
+
if (event !== undefined) {
|
|
77
|
+
subscriber.bytes -= bytes(event);
|
|
78
|
+
if (subscriber.closeAfterDrain && subscriber.queue.length === 0)
|
|
79
|
+
this.#close(subscriber);
|
|
80
|
+
return event;
|
|
81
|
+
}
|
|
82
|
+
if (signal.aborted)
|
|
83
|
+
return null;
|
|
84
|
+
await new Promise((resolve) => {
|
|
85
|
+
const done = () => {
|
|
86
|
+
signal.removeEventListener('abort', done);
|
|
87
|
+
subscriber.wake = undefined;
|
|
88
|
+
resolve();
|
|
89
|
+
};
|
|
90
|
+
subscriber.wake = done;
|
|
91
|
+
signal.addEventListener('abort', done, { once: true });
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
#enqueue(subscriber, event) {
|
|
97
|
+
const eventBytes = bytes(event);
|
|
98
|
+
if (subscriber.queue.length >= this.#limits.maxBufferedEvents || subscriber.bytes + eventBytes > this.#limits.maxBufferedBytes) {
|
|
99
|
+
const overflow = {
|
|
100
|
+
...event,
|
|
101
|
+
id: id('event'),
|
|
102
|
+
type: 'snapshot.required',
|
|
103
|
+
payload: { reason: 'buffer_overflow' }
|
|
104
|
+
};
|
|
105
|
+
subscriber.queue.splice(0, subscriber.queue.length, overflow);
|
|
106
|
+
subscriber.bytes = bytes(overflow);
|
|
107
|
+
subscriber.closeAfterDrain = true;
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
subscriber.queue.push(event);
|
|
111
|
+
subscriber.bytes += eventBytes;
|
|
112
|
+
}
|
|
113
|
+
subscriber.wake?.();
|
|
114
|
+
}
|
|
115
|
+
#close(subscriber) {
|
|
116
|
+
if (subscriber.closed)
|
|
117
|
+
return;
|
|
118
|
+
subscriber.closed = true;
|
|
119
|
+
this.#subscribers.delete(subscriber.id);
|
|
120
|
+
subscriber.wake?.();
|
|
121
|
+
this.#lifecycle.emit('closed', subscriber.id);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** The internal aliases `ChangedEntity` carries for the publisher's own use; 07 does not define them. */
|
|
125
|
+
const INTERNAL_CHANGE_KEYS = new Set(['type', 'id']);
|
|
126
|
+
function wireChange(entry) {
|
|
127
|
+
return Object.fromEntries(Object.entries(entry).filter(([key]) => !INTERNAL_CHANGE_KEYS.has(key)));
|
|
128
|
+
}
|
|
129
|
+
function bytes(event) {
|
|
130
|
+
return Buffer.byteLength(JSON.stringify(event));
|
|
131
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type CapabilityAdapter, type CapabilityInvocation, type CapabilityOutput } from '../core/domain.js';
|
|
2
|
+
import type { ConfigRuntime } from '../config/runtime.js';
|
|
3
|
+
import type { Document, Store } from '../store/store.js';
|
|
4
|
+
import type { RegisteredCapability, CapabilityRegistry } from './capabilities.js';
|
|
5
|
+
export declare class KernelAdapter implements CapabilityAdapter {
|
|
6
|
+
#private;
|
|
7
|
+
readonly store: Store;
|
|
8
|
+
readonly registry: CapabilityRegistry;
|
|
9
|
+
readonly config: ConfigRuntime;
|
|
10
|
+
readonly wakeAgent: (projectId: string, agentId: string) => void;
|
|
11
|
+
readonly createSubagent: (projectId: string, input: {
|
|
12
|
+
readonly parentAgentId: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly forkContext: 'full' | 'compact' | 'none';
|
|
15
|
+
readonly model?: string;
|
|
16
|
+
readonly modelReasoningEffort?: string;
|
|
17
|
+
readonly initialPrompt?: string;
|
|
18
|
+
readonly initialMessage?: string;
|
|
19
|
+
}, signal: AbortSignal) => Promise<Document>;
|
|
20
|
+
readonly id = "kernel";
|
|
21
|
+
constructor(store: Store, registry: CapabilityRegistry, config: ConfigRuntime, wakeAgent: (projectId: string, agentId: string) => void, createSubagent: (projectId: string, input: {
|
|
22
|
+
readonly parentAgentId: string;
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly forkContext: 'full' | 'compact' | 'none';
|
|
25
|
+
readonly model?: string;
|
|
26
|
+
readonly modelReasoningEffort?: string;
|
|
27
|
+
readonly initialPrompt?: string;
|
|
28
|
+
readonly initialMessage?: string;
|
|
29
|
+
}, signal: AbortSignal) => Promise<Document>);
|
|
30
|
+
execute(invocation: CapabilityInvocation): Promise<CapabilityOutput>;
|
|
31
|
+
}
|
|
32
|
+
export declare function kernelCapabilities(adapter: KernelAdapter): readonly RegisteredCapability[];
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { jsonValue } from '../core/codec.js';
|
|
2
|
+
import { UserInputRequiredError, fail } from '../core/domain.js';
|
|
3
|
+
import { capabilityManifest } from './manifests.js';
|
|
4
|
+
export class KernelAdapter {
|
|
5
|
+
store;
|
|
6
|
+
registry;
|
|
7
|
+
config;
|
|
8
|
+
wakeAgent;
|
|
9
|
+
createSubagent;
|
|
10
|
+
id = 'kernel';
|
|
11
|
+
constructor(store, registry, config, wakeAgent, createSubagent) {
|
|
12
|
+
this.store = store;
|
|
13
|
+
this.registry = registry;
|
|
14
|
+
this.config = config;
|
|
15
|
+
this.wakeAgent = wakeAgent;
|
|
16
|
+
this.createSubagent = createSubagent;
|
|
17
|
+
}
|
|
18
|
+
execute(invocation) {
|
|
19
|
+
const envelope = object(invocation.arguments);
|
|
20
|
+
const input = envelope.arguments === undefined
|
|
21
|
+
? envelope
|
|
22
|
+
: { ...object(jsonValue(envelope.arguments)), ...(envelope.answer === undefined ? {} : { answer: envelope.answer }) };
|
|
23
|
+
if (invocation.capabilityId === 'system_echo')
|
|
24
|
+
return output(jsonValue(input));
|
|
25
|
+
if (invocation.capabilityId === 'programmatic_tool_run')
|
|
26
|
+
fail('ADAPTER_INCOMPATIBLE', 503, 'Programmatic Tool Calling must be executed by a supported Provider.');
|
|
27
|
+
if (invocation.capabilityId === 'capability_search') {
|
|
28
|
+
const assigned = invocation.agentId === null
|
|
29
|
+
? null
|
|
30
|
+
: new Set(this.store.listCapabilities(invocation.projectId, invocation.agentId).map((entry) => string(entry.capability_id)));
|
|
31
|
+
const matches = this.registry.search(text(input.query, 'query'), optionalInteger(input.limit) ?? 20)
|
|
32
|
+
.filter((entry) => assigned === null || assigned.has(entry.id));
|
|
33
|
+
const requested = optionalStrings(input.load);
|
|
34
|
+
if (requested.some((capabilityId) => !matches.some((entry) => entry.id === capabilityId))) {
|
|
35
|
+
fail('CAPABILITY_ARGUMENT_INVALID', 400, 'A requested Capability was not returned by this search.');
|
|
36
|
+
}
|
|
37
|
+
if (requested.length > 0) {
|
|
38
|
+
const agentId = invocation.agentId;
|
|
39
|
+
if (agentId === null)
|
|
40
|
+
fail('AGENT_REQUIRED', 409, 'Loading a Capability requires an Agent.');
|
|
41
|
+
this.store.loadCapabilities(invocation.projectId, agentId, Object.fromEntries(requested.map((capabilityId) => {
|
|
42
|
+
const definition = this.registry.get(capabilityId);
|
|
43
|
+
return [capabilityId, definition.effect === 'read_only' ? 'read_only' : 'ask'];
|
|
44
|
+
})));
|
|
45
|
+
}
|
|
46
|
+
return output({ matches: matches, loaded: requested, effective_from: 'next_eligible_model_attempt' });
|
|
47
|
+
}
|
|
48
|
+
const agentId = invocation.agentId;
|
|
49
|
+
if (agentId === null)
|
|
50
|
+
fail('AGENT_REQUIRED', 409, 'This Capability requires an Agent.');
|
|
51
|
+
if (invocation.capabilityId === 'update_plan' || invocation.capabilityId === 'update_todo') {
|
|
52
|
+
return output(this.store.updatePlan(invocation.projectId, agentId, jsonValue(input.items ?? [])));
|
|
53
|
+
}
|
|
54
|
+
if (invocation.capabilityId === 'ask_user') {
|
|
55
|
+
if (input.answer === undefined)
|
|
56
|
+
throw new UserInputRequiredError({
|
|
57
|
+
kind: 'question',
|
|
58
|
+
question: text(input.question, 'question'),
|
|
59
|
+
options: jsonValue(input.options ?? []),
|
|
60
|
+
allow_freeform: input.allow_freeform !== false,
|
|
61
|
+
multi_select: input.multi_select === true
|
|
62
|
+
});
|
|
63
|
+
return output({ answer: jsonValue(input.answer) });
|
|
64
|
+
}
|
|
65
|
+
if (invocation.capabilityId === 'compact') {
|
|
66
|
+
const document = this.store.compactContext(invocation.projectId, agentId, text(input.summary, 'summary'), integer(input.preserve_from_ordinal, 'preserve_from_ordinal'));
|
|
67
|
+
return output(document);
|
|
68
|
+
}
|
|
69
|
+
if (invocation.capabilityId === 'subagent_create')
|
|
70
|
+
return this.#createSubagent(invocation.projectId, agentId, input, invocation.signal);
|
|
71
|
+
if (invocation.capabilityId === 'subagent_message')
|
|
72
|
+
return this.#messageSubagent(invocation.projectId, agentId, input);
|
|
73
|
+
if (invocation.capabilityId === 'subagent_broadcast')
|
|
74
|
+
return this.#broadcast(invocation.projectId, agentId, input);
|
|
75
|
+
if (invocation.capabilityId === 'subagent_wait') {
|
|
76
|
+
return this.store.waitForSubagent(invocation.projectId, agentId, text(input.target_agent_id, 'target_agent_id'), optionalInteger(input.timeout_ms) ?? 30000, invocation.signal).then(output);
|
|
77
|
+
}
|
|
78
|
+
if (invocation.capabilityId === 'slash_command_list') {
|
|
79
|
+
return output({ commands: this.registry.list().filter((entry) => entry.kind === 'command').map((entry) => ({ name: `/${entry.id}`, capability_id: entry.id, description: entry.description })) });
|
|
80
|
+
}
|
|
81
|
+
if (invocation.capabilityId === 'slash_command_run') {
|
|
82
|
+
const commandId = text(input.command, 'command').replace(/^\/+/, '');
|
|
83
|
+
const definition = this.registry.find(commandId);
|
|
84
|
+
if (definition?.kind !== 'command')
|
|
85
|
+
fail('SLASH_COMMAND_NOT_FOUND', 404, 'The requested slash command is not registered.');
|
|
86
|
+
return this.registry.execute({ ...invocation, capabilityId: commandId, arguments: jsonValue(input.arguments ?? {}) });
|
|
87
|
+
}
|
|
88
|
+
fail('CAPABILITY_NOT_FOUND', 404, 'The Kernel Capability does not exist.');
|
|
89
|
+
}
|
|
90
|
+
#createSubagent(projectId, parentAgentId, input, signal) {
|
|
91
|
+
const forkContext = input.forkContext;
|
|
92
|
+
if (forkContext !== 'full' && forkContext !== 'compact' && forkContext !== 'none')
|
|
93
|
+
fail('INVALID_INPUT', 400, 'forkContext is required.');
|
|
94
|
+
return this.createSubagent(projectId, {
|
|
95
|
+
parentAgentId,
|
|
96
|
+
name: text(input.name, 'name'),
|
|
97
|
+
forkContext,
|
|
98
|
+
...(typeof input.model === 'string' ? { model: input.model } : {}),
|
|
99
|
+
...(typeof input.modelReasoningEffort === 'string' ? { modelReasoningEffort: input.modelReasoningEffort } : {}),
|
|
100
|
+
...(typeof input.initialPrompt === 'string' ? { initialPrompt: input.initialPrompt } : {}),
|
|
101
|
+
...(typeof input.message === 'string' ? { initialMessage: input.message } : {})
|
|
102
|
+
}, signal).then(output);
|
|
103
|
+
}
|
|
104
|
+
#messageSubagent(projectId, sourceAgentId, input) {
|
|
105
|
+
const targetId = text(input.agent_id, 'agent_id');
|
|
106
|
+
if (this.store.getAgent(projectId, targetId).parent_agent_id !== sourceAgentId)
|
|
107
|
+
fail('SUBAGENT_TARGET_INVALID', 422, 'The target is not a direct child Agent.');
|
|
108
|
+
const message = this.store.enqueueMessage(projectId, targetId, text(input.content, 'content'), sourceAgentId);
|
|
109
|
+
this.wakeAgent(projectId, targetId);
|
|
110
|
+
return output(message);
|
|
111
|
+
}
|
|
112
|
+
#broadcast(projectId, sourceAgentId, input) {
|
|
113
|
+
const source = this.store.getAgent(projectId, sourceAgentId);
|
|
114
|
+
const content = text(input.content, 'content');
|
|
115
|
+
const targets = this.store.listAgents(projectId, 'task_id', string(source.task_id)).filter((entry) => entry.parent_agent_id === sourceAgentId);
|
|
116
|
+
const messages = targets.map((target) => {
|
|
117
|
+
const targetId = string(target.id);
|
|
118
|
+
const message = this.store.enqueueMessage(projectId, targetId, content, sourceAgentId);
|
|
119
|
+
this.wakeAgent(projectId, targetId);
|
|
120
|
+
return message.message;
|
|
121
|
+
});
|
|
122
|
+
return output({ messages });
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export function kernelCapabilities(adapter) {
|
|
126
|
+
return definitions.map((definition) => ({
|
|
127
|
+
definition,
|
|
128
|
+
adapter,
|
|
129
|
+
manifest: capabilityManifest(definition),
|
|
130
|
+
claims: () => definition.effect === 'read_only' ? [] : [{ resource: `agent:${definition.id}`, mode: 'write' }]
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
const stringSchema = { type: 'string', minLength: 1 };
|
|
134
|
+
const integerSchema = { type: 'integer', minimum: 0 };
|
|
135
|
+
const kernelOutputLimits = {
|
|
136
|
+
programmatic_tool_run: 1048576, system_echo: 1048576, compact: 1048576, slash_command_list: 524288, slash_command_run: 1048576
|
|
137
|
+
};
|
|
138
|
+
const definitions = [
|
|
139
|
+
definition('capability_search', 'Search capabilities', 'Find and load capabilities available to the Agent.', 'read_only', { query: stringSchema, limit: integerSchema, load: { type: 'array', items: stringSchema } }, ['query']),
|
|
140
|
+
definition('programmatic_tool_run', 'Run hosted tool program', 'Coordinate frozen capabilities in the Provider hosted program runtime.', 'full', { program: stringSchema, capabilityIds: { type: 'array', items: stringSchema } }, ['program', 'capabilityIds']),
|
|
141
|
+
definition('system_echo', 'Echo', 'Return the supplied JSON input.', 'read_only', {}, []),
|
|
142
|
+
definition('update_plan', 'Update plan', 'Replace the Agent plan items.', 'workspace_write', { items: { type: 'array' } }, ['items']),
|
|
143
|
+
definition('update_todo', 'Update todo', 'Replace the Agent todo items.', 'workspace_write', { items: { type: 'array' } }, ['items']),
|
|
144
|
+
definition('ask_user', 'Ask user', 'Pause until the user supplies an answer.', 'read_only', {
|
|
145
|
+
question: stringSchema,
|
|
146
|
+
options: { type: 'array', maxItems: 100, items: { type: 'object', additionalProperties: false, properties: { label: stringSchema, value: stringSchema, description: { type: 'string' } }, required: ['label', 'value'] } },
|
|
147
|
+
allow_freeform: { type: 'boolean' },
|
|
148
|
+
multi_select: { type: 'boolean' }
|
|
149
|
+
}, ['question']),
|
|
150
|
+
definition('compact', 'Compact context', 'Append a Context compaction summary.', 'workspace_write', { summary: stringSchema, preserve_from_ordinal: integerSchema }, ['summary', 'preserve_from_ordinal'], 'command'),
|
|
151
|
+
definition('subagent_create', 'Create subagent', 'Create a child Agent in the same Task.', 'workspace_write', {
|
|
152
|
+
name: stringSchema,
|
|
153
|
+
forkContext: { type: 'string', enum: ['full', 'compact', 'none'] },
|
|
154
|
+
model: stringSchema,
|
|
155
|
+
modelReasoningEffort: stringSchema,
|
|
156
|
+
initialPrompt: stringSchema,
|
|
157
|
+
message: stringSchema
|
|
158
|
+
}, ['name', 'forkContext']),
|
|
159
|
+
definition('subagent_message', 'Message subagent', 'Send a copied Message to one child Agent.', 'workspace_write', { agent_id: stringSchema, content: stringSchema }, ['agent_id', 'content']),
|
|
160
|
+
definition('subagent_broadcast', 'Broadcast to subagents', 'Send a copied Message to every direct child Agent.', 'workspace_write', { content: stringSchema }, ['content']),
|
|
161
|
+
definition('subagent_wait', 'Wait for subagent', 'Wait for a Subagent message or terminal state.', 'read_only', { target_agent_id: stringSchema, timeout_ms: { type: 'integer', minimum: 1, maximum: 120000 } }, ['target_agent_id']),
|
|
162
|
+
definition('slash_command_list', 'List slash commands', 'List available control commands.', 'read_only', {}, []),
|
|
163
|
+
definition('slash_command_run', 'Run slash command', 'Run a control command.', 'workspace_write', { command: stringSchema }, ['command'])
|
|
164
|
+
];
|
|
165
|
+
function definition(id, title, description, effect, properties, required, kind = 'tool') {
|
|
166
|
+
return { id, title, description, effect, adapterId: 'kernel', loadMode: 'eager', outputLimitBytes: kernelOutputLimits[id] ?? 262144, defaultAssignment: 'all_new_agents', kind, inputSchema: { type: 'object', additionalProperties: true, properties, required } };
|
|
167
|
+
}
|
|
168
|
+
function output(content) {
|
|
169
|
+
return Promise.resolve({ content: content });
|
|
170
|
+
}
|
|
171
|
+
function object(value) {
|
|
172
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
173
|
+
fail('INVALID_INPUT', 400, 'Capability input must be an object.');
|
|
174
|
+
return value;
|
|
175
|
+
}
|
|
176
|
+
function text(value, field) {
|
|
177
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
178
|
+
fail('INVALID_INPUT', 400, `${field} must be a non-empty string.`);
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
function integer(value, field) {
|
|
182
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)
|
|
183
|
+
fail('INVALID_INPUT', 400, `${field} must be a non-negative integer.`);
|
|
184
|
+
return value;
|
|
185
|
+
}
|
|
186
|
+
function optionalInteger(value) {
|
|
187
|
+
return value === undefined ? undefined : integer(value, 'limit');
|
|
188
|
+
}
|
|
189
|
+
function optionalStrings(value) {
|
|
190
|
+
if (value === undefined)
|
|
191
|
+
return [];
|
|
192
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string'))
|
|
193
|
+
fail('INVALID_INPUT', 400, 'load must be a string array.');
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
function string(value) {
|
|
197
|
+
if (typeof value !== 'string')
|
|
198
|
+
fail('DATABASE_CORRUPT', 503, 'Agent data is invalid.');
|
|
199
|
+
return value;
|
|
200
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AdapterManifest, type AdapterPlatform, type AdapterRuntime, type CapabilityDefinition, type EffectScope } from '../core/domain.js';
|
|
2
|
+
import { type HarnessConfig } from '../config/schema.js';
|
|
3
|
+
export interface AdapterTarget {
|
|
4
|
+
readonly platform: AdapterPlatform;
|
|
5
|
+
readonly runtime: AdapterRuntime;
|
|
6
|
+
}
|
|
7
|
+
export declare function adapterTarget(runtime: AdapterRuntime): AdapterTarget;
|
|
8
|
+
export declare function capabilityManifest(definition: CapabilityDefinition, effectScopes?: readonly EffectScope[]): AdapterManifest;
|
|
9
|
+
export declare function providerManifest(config: HarnessConfig, providerId: string): AdapterManifest;
|
|
10
|
+
export declare function coreManifests(config: HarnessConfig): readonly AdapterManifest[];
|
|
11
|
+
export declare function assertCapabilityManifest(manifest: AdapterManifest, definition: CapabilityDefinition, target: AdapterTarget): void;
|
|
12
|
+
export declare function assertProviderManifest(manifest: AdapterManifest, reference: string, target: AdapterTarget): void;
|
|
13
|
+
export declare function assertManifestSet(manifests: readonly AdapterManifest[], target: AdapterTarget): void;
|
|
14
|
+
export declare function manifestSetDigest(manifests: readonly AdapterManifest[], target: AdapterTarget): string;
|