@replayci/replay 0.1.16 → 0.1.18
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/dist/index.cjs +421 -54
- package/dist/index.d.cts +33 -4
- package/dist/index.d.ts +33 -4
- package/dist/index.js +421 -54
- package/package.json +4 -2
package/dist/index.cjs
CHANGED
|
@@ -5213,7 +5213,9 @@ var RuntimeClient = class {
|
|
|
5213
5213
|
accepted: r.accepted,
|
|
5214
5214
|
commitState: r.commit_state,
|
|
5215
5215
|
stateAdvanced: r.state_advanced,
|
|
5216
|
-
stateVersion: r.state_version
|
|
5216
|
+
stateVersion: r.state_version,
|
|
5217
|
+
executionState: r.execution_state ?? "outcome_recorded",
|
|
5218
|
+
pendingStatus: r.pending_status ?? (r.state_advanced ? "resolved" : "pending")
|
|
5217
5219
|
};
|
|
5218
5220
|
}
|
|
5219
5221
|
async setToolFilter(input) {
|
|
@@ -5474,6 +5476,7 @@ var DEFAULT_AGENT2 = "default";
|
|
|
5474
5476
|
var DEFAULT_MAX_UNGUARDED_CALLS = 3;
|
|
5475
5477
|
function replay(client, opts = {}) {
|
|
5476
5478
|
assertSupportedNodeRuntime();
|
|
5479
|
+
const internalOpts = opts;
|
|
5477
5480
|
const sessionId = opts.sessionId ?? generateSessionId2();
|
|
5478
5481
|
const agent = typeof opts.agent === "string" && opts.agent.length > 0 ? opts.agent : DEFAULT_AGENT2;
|
|
5479
5482
|
const mode = opts.mode ?? "enforce";
|
|
@@ -5495,17 +5498,20 @@ function replay(client, opts = {}) {
|
|
|
5495
5498
|
return createInactiveSession(client, sessionId, "Client already has an active observe() or replay() attachment");
|
|
5496
5499
|
}
|
|
5497
5500
|
let contracts;
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5501
|
+
if (internalOpts.__preparedContracts && internalOpts.__preparedContracts.length > 0) {
|
|
5502
|
+
contracts = internalOpts.__preparedContracts;
|
|
5503
|
+
} else {
|
|
5504
|
+
try {
|
|
5505
|
+
contracts = resolveContracts(opts);
|
|
5506
|
+
} catch (err) {
|
|
5507
|
+
const apiKeyForGov = resolveApiKey2(opts);
|
|
5508
|
+
if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
|
|
5509
|
+
return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
|
|
5510
|
+
}
|
|
5511
|
+
const detail = err instanceof Error ? err.message : "Failed to load contracts";
|
|
5512
|
+
emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
|
|
5513
|
+
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5505
5514
|
}
|
|
5506
|
-
const detail = err instanceof Error ? err.message : "Failed to load contracts";
|
|
5507
|
-
emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
|
|
5508
|
-
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5509
5515
|
}
|
|
5510
5516
|
const configError = validateConfig(contracts, opts);
|
|
5511
5517
|
if (configError) {
|
|
@@ -5532,20 +5538,22 @@ function replay(client, opts = {}) {
|
|
|
5532
5538
|
} else if (sessionYaml && opts.providerConstraints && !sessionYaml.provider_constraints) {
|
|
5533
5539
|
sessionYaml = { ...sessionYaml, provider_constraints: opts.providerConstraints };
|
|
5534
5540
|
}
|
|
5535
|
-
let compiledSession = null;
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5541
|
+
let compiledSession = internalOpts.__compiledSession ?? null;
|
|
5542
|
+
if (!compiledSession) {
|
|
5543
|
+
try {
|
|
5544
|
+
compiledSession = (0, import_contracts_core7.compileSession)(contracts, sessionYaml, {
|
|
5545
|
+
principal: opts.principal,
|
|
5546
|
+
tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
|
|
5547
|
+
});
|
|
5548
|
+
} catch (err) {
|
|
5549
|
+
const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
5550
|
+
emitDiagnostic2(diagnostics, {
|
|
5551
|
+
type: "replay_compile_error",
|
|
5552
|
+
details: detail
|
|
5553
|
+
});
|
|
5554
|
+
if (discoveredSessionYaml) {
|
|
5555
|
+
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5556
|
+
}
|
|
5549
5557
|
}
|
|
5550
5558
|
}
|
|
5551
5559
|
if (compiledSession?.warnings && compiledSession.warnings.length > 0) {
|
|
@@ -5612,7 +5620,7 @@ function replay(client, opts = {}) {
|
|
|
5612
5620
|
return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
|
|
5613
5621
|
}
|
|
5614
5622
|
const apiKey = resolveApiKey2(opts);
|
|
5615
|
-
const protectionLevel = determineProtectionLevel(mode, opts.tools, contracts, apiKey);
|
|
5623
|
+
const protectionLevel = internalOpts.__disableRuntimeControlPlane ? determineRuntimeFreeProtectionLevel(mode) : determineProtectionLevel(mode, opts.tools, contracts, apiKey);
|
|
5616
5624
|
const maxUnguardedCalls = opts.maxUnguardedCalls ?? DEFAULT_MAX_UNGUARDED_CALLS;
|
|
5617
5625
|
const narrowingFeedback = opts.narrowingFeedback ?? "silent";
|
|
5618
5626
|
let runtimeClient = null;
|
|
@@ -7971,6 +7979,185 @@ function createBlockingInactiveSession(client, sessionId, detail, configError) {
|
|
|
7971
7979
|
handoff: () => Promise.resolve(null)
|
|
7972
7980
|
};
|
|
7973
7981
|
}
|
|
7982
|
+
function createPreparedContractsFromCompiledSession(compiledSession) {
|
|
7983
|
+
return Array.from(compiledSession.perToolContracts.values()).map((contract) => ({
|
|
7984
|
+
...contract,
|
|
7985
|
+
contract_file: contract.tool
|
|
7986
|
+
}));
|
|
7987
|
+
}
|
|
7988
|
+
function requireArtifactRecord(value, field) {
|
|
7989
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7990
|
+
throw new ReplayConfigError(
|
|
7991
|
+
"compilation_failed",
|
|
7992
|
+
`Approved governance artifact has invalid ${field}`
|
|
7993
|
+
);
|
|
7994
|
+
}
|
|
7995
|
+
return value;
|
|
7996
|
+
}
|
|
7997
|
+
function requireArtifactStringArray(value, field) {
|
|
7998
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
7999
|
+
throw new ReplayConfigError(
|
|
8000
|
+
"compilation_failed",
|
|
8001
|
+
`Approved governance artifact has invalid ${field}`
|
|
8002
|
+
);
|
|
8003
|
+
}
|
|
8004
|
+
return value;
|
|
8005
|
+
}
|
|
8006
|
+
function requireArtifactEntryArray(value, field) {
|
|
8007
|
+
if (!Array.isArray(value)) {
|
|
8008
|
+
throw new ReplayConfigError(
|
|
8009
|
+
"compilation_failed",
|
|
8010
|
+
`Approved governance artifact has invalid ${field}`
|
|
8011
|
+
);
|
|
8012
|
+
}
|
|
8013
|
+
return value.map((entry) => {
|
|
8014
|
+
if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") {
|
|
8015
|
+
throw new ReplayConfigError(
|
|
8016
|
+
"compilation_failed",
|
|
8017
|
+
`Approved governance artifact has invalid ${field}`
|
|
8018
|
+
);
|
|
8019
|
+
}
|
|
8020
|
+
return [entry[0], entry[1]];
|
|
8021
|
+
});
|
|
8022
|
+
}
|
|
8023
|
+
function hydrateStringArrayMap(value, field) {
|
|
8024
|
+
return new Map(
|
|
8025
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
|
|
8026
|
+
key,
|
|
8027
|
+
requireArtifactStringArray(entryValue, `${field}.${key}`)
|
|
8028
|
+
])
|
|
8029
|
+
);
|
|
8030
|
+
}
|
|
8031
|
+
function hydrateContractMap(value, field) {
|
|
8032
|
+
return new Map(
|
|
8033
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
|
|
8034
|
+
key,
|
|
8035
|
+
requireArtifactRecord(entryValue, `${field}.${key}`)
|
|
8036
|
+
])
|
|
8037
|
+
);
|
|
8038
|
+
}
|
|
8039
|
+
function hydrateExecutionConstraintMap(value, field) {
|
|
8040
|
+
return new Map(
|
|
8041
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => {
|
|
8042
|
+
if (!Array.isArray(entryValue)) {
|
|
8043
|
+
throw new ReplayConfigError(
|
|
8044
|
+
"compilation_failed",
|
|
8045
|
+
`Approved governance artifact has invalid ${field}.${key}`
|
|
8046
|
+
);
|
|
8047
|
+
}
|
|
8048
|
+
return [key, entryValue];
|
|
8049
|
+
})
|
|
8050
|
+
);
|
|
8051
|
+
}
|
|
8052
|
+
function hydrateNestedStringMap(value, field) {
|
|
8053
|
+
return new Map(
|
|
8054
|
+
requireArtifactEntryArray(value, field).map(([outerKey, innerValue]) => {
|
|
8055
|
+
const nested = new Map(
|
|
8056
|
+
requireArtifactEntryArray(innerValue, `${field}.${outerKey}`).map(([innerKey, nestedValue]) => {
|
|
8057
|
+
if (typeof nestedValue !== "string") {
|
|
8058
|
+
throw new ReplayConfigError(
|
|
8059
|
+
"compilation_failed",
|
|
8060
|
+
`Approved governance artifact has invalid ${field}.${outerKey}.${innerKey}`
|
|
8061
|
+
);
|
|
8062
|
+
}
|
|
8063
|
+
return [innerKey, nestedValue];
|
|
8064
|
+
})
|
|
8065
|
+
);
|
|
8066
|
+
return [outerKey, nested];
|
|
8067
|
+
})
|
|
8068
|
+
);
|
|
8069
|
+
}
|
|
8070
|
+
function hydratePolicyProgram(value) {
|
|
8071
|
+
if (value == null) return null;
|
|
8072
|
+
const policyProgram = requireArtifactRecord(value, "policyProgram");
|
|
8073
|
+
if (typeof policyProgram.defaultDeny !== "boolean" || !Array.isArray(policyProgram.sessionRules)) {
|
|
8074
|
+
throw new ReplayConfigError(
|
|
8075
|
+
"compilation_failed",
|
|
8076
|
+
"Approved governance artifact has invalid policyProgram"
|
|
8077
|
+
);
|
|
8078
|
+
}
|
|
8079
|
+
return {
|
|
8080
|
+
defaultDeny: policyProgram.defaultDeny,
|
|
8081
|
+
sessionRules: policyProgram.sessionRules,
|
|
8082
|
+
perToolRules: new Map(
|
|
8083
|
+
requireArtifactEntryArray(policyProgram.perToolRules ?? [], "policyProgram.perToolRules").map(
|
|
8084
|
+
([toolName, ruleValue]) => [toolName, requireArtifactRecord(ruleValue, `policyProgram.perToolRules.${toolName}`)]
|
|
8085
|
+
)
|
|
8086
|
+
)
|
|
8087
|
+
};
|
|
8088
|
+
}
|
|
8089
|
+
function rehydrateCompiledSessionArtifact(artifact, expectedHash) {
|
|
8090
|
+
const record = requireArtifactRecord(artifact, "compiled_session");
|
|
8091
|
+
if (typeof record.agent !== "string" || typeof record.schemaVersion !== "string") {
|
|
8092
|
+
throw new ReplayConfigError(
|
|
8093
|
+
"compilation_failed",
|
|
8094
|
+
"Approved governance artifact is missing required session metadata"
|
|
8095
|
+
);
|
|
8096
|
+
}
|
|
8097
|
+
if (record.phases != null && !Array.isArray(record.phases)) {
|
|
8098
|
+
throw new ReplayConfigError(
|
|
8099
|
+
"compilation_failed",
|
|
8100
|
+
"Approved governance artifact has invalid phases"
|
|
8101
|
+
);
|
|
8102
|
+
}
|
|
8103
|
+
if (!Array.isArray(record.contractHashes) || record.contractHashes.some((hash) => typeof hash !== "string")) {
|
|
8104
|
+
throw new ReplayConfigError(
|
|
8105
|
+
"compilation_failed",
|
|
8106
|
+
"Approved governance artifact has invalid contractHashes"
|
|
8107
|
+
);
|
|
8108
|
+
}
|
|
8109
|
+
const compiledSession = {
|
|
8110
|
+
agent: record.agent,
|
|
8111
|
+
schemaVersion: record.schemaVersion,
|
|
8112
|
+
phases: record.phases ?? null,
|
|
8113
|
+
transitions: hydrateStringArrayMap(record.transitions ?? [], "transitions"),
|
|
8114
|
+
sessionLimits: record.sessionLimits ?? {},
|
|
8115
|
+
perToolContracts: hydrateContractMap(record.perToolContracts ?? [], "perToolContracts"),
|
|
8116
|
+
riskDefaults: requireArtifactRecord(record.riskDefaults ?? {}, "riskDefaults"),
|
|
8117
|
+
providerConstraints: record.providerConstraints ?? null,
|
|
8118
|
+
contractHashes: record.contractHashes,
|
|
8119
|
+
compiledHash: "",
|
|
8120
|
+
principal: null,
|
|
8121
|
+
policyProgram: hydratePolicyProgram(record.policyProgram),
|
|
8122
|
+
executionConstraints: hydrateExecutionConstraintMap(record.executionConstraints ?? [], "executionConstraints"),
|
|
8123
|
+
toolExecutors: null,
|
|
8124
|
+
resources: hydrateNestedStringMap(record.resources ?? [], "resources"),
|
|
8125
|
+
warnings: [],
|
|
8126
|
+
graphDiagnostics: [],
|
|
8127
|
+
schemaDerivedDiagnostics: [],
|
|
8128
|
+
aggregates: Array.isArray(record.aggregates) ? record.aggregates : [],
|
|
8129
|
+
envelopes: Array.isArray(record.envelopes) ? record.envelopes : [],
|
|
8130
|
+
labelGates: Array.isArray(record.labelGates) ? record.labelGates : [],
|
|
8131
|
+
checkpoints: Array.isArray(record.checkpoints) ? record.checkpoints : []
|
|
8132
|
+
};
|
|
8133
|
+
const serialized = (0, import_contracts_core7.serializeCompiledSession)(compiledSession);
|
|
8134
|
+
const computedHash = import_node_crypto6.default.createHash("sha256").update(serialized).digest("hex");
|
|
8135
|
+
compiledSession.compiledHash = computedHash;
|
|
8136
|
+
if (expectedHash && expectedHash !== computedHash) {
|
|
8137
|
+
throw new ReplayConfigError(
|
|
8138
|
+
"compilation_failed",
|
|
8139
|
+
`Approved governance artifact hash mismatch: expected ${expectedHash}, got ${computedHash}`
|
|
8140
|
+
);
|
|
8141
|
+
}
|
|
8142
|
+
return compiledSession;
|
|
8143
|
+
}
|
|
8144
|
+
function createDetachedProviderClient(provider, terminal, originalCreate) {
|
|
8145
|
+
const boundCreate = (...args) => originalCreate.apply(terminal, args);
|
|
8146
|
+
if (provider === "openai") {
|
|
8147
|
+
return {
|
|
8148
|
+
chat: {
|
|
8149
|
+
completions: {
|
|
8150
|
+
create: boundCreate
|
|
8151
|
+
}
|
|
8152
|
+
}
|
|
8153
|
+
};
|
|
8154
|
+
}
|
|
8155
|
+
return {
|
|
8156
|
+
messages: {
|
|
8157
|
+
create: boundCreate
|
|
8158
|
+
}
|
|
8159
|
+
};
|
|
8160
|
+
}
|
|
7974
8161
|
function resolveGovernanceEnvironment(opts) {
|
|
7975
8162
|
if (opts.environment) return opts.environment;
|
|
7976
8163
|
const envVar = typeof process !== "undefined" ? process.env.REPLAYCI_ENVIRONMENT : void 0;
|
|
@@ -7993,7 +8180,7 @@ function governanceProtectionLevel(env) {
|
|
|
7993
8180
|
}
|
|
7994
8181
|
function createGovernanceSession(client, sessionId, agent, provider, apiKey, opts, diagnostics) {
|
|
7995
8182
|
const environment = resolveGovernanceEnvironment(opts);
|
|
7996
|
-
const
|
|
8183
|
+
const observeProtectionLevel = governanceProtectionLevel(environment);
|
|
7997
8184
|
const runtimeClient = new RuntimeClient({
|
|
7998
8185
|
apiKey,
|
|
7999
8186
|
apiUrl: opts.runtimeUrl
|
|
@@ -8002,13 +8189,22 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
8002
8189
|
let planFetchPromise = null;
|
|
8003
8190
|
let planFetchDone = false;
|
|
8004
8191
|
let planFetchError = null;
|
|
8192
|
+
let planFetchErrorCode = null;
|
|
8193
|
+
let approvedRuntimeSession = null;
|
|
8194
|
+
let approvedRuntimeInitPromise = null;
|
|
8195
|
+
let approvedRuntimeInitError = null;
|
|
8005
8196
|
planFetchPromise = runtimeClient.fetchGovernancePlan(agent, environment).then((result) => {
|
|
8006
8197
|
governancePlan = result;
|
|
8007
8198
|
planFetchDone = true;
|
|
8199
|
+
if (!hasApprovedGovernanceArtifact(result)) {
|
|
8200
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_no_plan", session_id: sessionId, environment });
|
|
8201
|
+
}
|
|
8008
8202
|
}).catch((err) => {
|
|
8009
8203
|
planFetchDone = true;
|
|
8010
8204
|
planFetchError = err instanceof Error ? err.message : String(err);
|
|
8205
|
+
planFetchErrorCode = err instanceof RuntimeClientError ? err.code : null;
|
|
8011
8206
|
governancePlan = null;
|
|
8207
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_fetch_failed", session_id: sessionId, details: planFetchError });
|
|
8012
8208
|
});
|
|
8013
8209
|
const captureBuffer = new CaptureBuffer({
|
|
8014
8210
|
apiKey,
|
|
@@ -8021,12 +8217,139 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
8021
8217
|
return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
|
|
8022
8218
|
}
|
|
8023
8219
|
const { terminal, originalCreate } = terminalInfo;
|
|
8220
|
+
const fallbackTools = buildWrappedToolsMap(opts.tools, null);
|
|
8221
|
+
function hasApprovedGovernanceArtifact(plan) {
|
|
8222
|
+
return Boolean(
|
|
8223
|
+
plan && (plan.status === "approved" || plan.status === "enforcing")
|
|
8224
|
+
);
|
|
8225
|
+
}
|
|
8226
|
+
async function ensureApprovedRuntimeSession() {
|
|
8227
|
+
if (approvedRuntimeSession) return approvedRuntimeSession;
|
|
8228
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8229
|
+
if (approvedRuntimeInitPromise) {
|
|
8230
|
+
await approvedRuntimeInitPromise;
|
|
8231
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8232
|
+
return approvedRuntimeSession;
|
|
8233
|
+
}
|
|
8234
|
+
approvedRuntimeInitPromise = (async () => {
|
|
8235
|
+
if (!hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8236
|
+
throw new ReplayConfigError(
|
|
8237
|
+
"compilation_failed",
|
|
8238
|
+
"Approved governance artifact was not available for runtime enforcement"
|
|
8239
|
+
);
|
|
8240
|
+
}
|
|
8241
|
+
if (!governancePlan?.compiledSession) {
|
|
8242
|
+
throw new ReplayConfigError(
|
|
8243
|
+
"compilation_failed",
|
|
8244
|
+
"Approved governance plan is missing compiled_session"
|
|
8245
|
+
);
|
|
8246
|
+
}
|
|
8247
|
+
if (!governancePlan.compiledHash) {
|
|
8248
|
+
throw new ReplayConfigError(
|
|
8249
|
+
"compilation_failed",
|
|
8250
|
+
"Approved governance plan is missing compiled_hash"
|
|
8251
|
+
);
|
|
8252
|
+
}
|
|
8253
|
+
const compiledSession = rehydrateCompiledSessionArtifact(
|
|
8254
|
+
governancePlan.compiledSession,
|
|
8255
|
+
governancePlan.compiledHash
|
|
8256
|
+
);
|
|
8257
|
+
const preparedContracts = createPreparedContractsFromCompiledSession(compiledSession);
|
|
8258
|
+
const detachedClient = createDetachedProviderClient(
|
|
8259
|
+
provider,
|
|
8260
|
+
terminal,
|
|
8261
|
+
originalCreate
|
|
8262
|
+
);
|
|
8263
|
+
const approvedMode = environment === "development" ? "shadow" : "enforce";
|
|
8264
|
+
const approvedCompatEnforcement = environment === "staging" ? "advisory" : opts.compatEnforcement ?? "protective";
|
|
8265
|
+
approvedRuntimeSession = replay(detachedClient, {
|
|
8266
|
+
...opts,
|
|
8267
|
+
agent,
|
|
8268
|
+
sessionId,
|
|
8269
|
+
apiKey,
|
|
8270
|
+
mode: approvedMode,
|
|
8271
|
+
compatEnforcement: approvedCompatEnforcement,
|
|
8272
|
+
contracts: void 0,
|
|
8273
|
+
contractsDir: void 0,
|
|
8274
|
+
sessionYamlPath: void 0,
|
|
8275
|
+
environment: void 0,
|
|
8276
|
+
__preparedContracts: preparedContracts,
|
|
8277
|
+
__compiledSession: compiledSession,
|
|
8278
|
+
__disableRuntimeControlPlane: true
|
|
8279
|
+
});
|
|
8280
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_attached", session_id: sessionId, environment });
|
|
8281
|
+
})().catch((err) => {
|
|
8282
|
+
approvedRuntimeInitError = err instanceof Error ? err : new ReplayConfigError("compilation_failed", String(err));
|
|
8283
|
+
const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
|
|
8284
|
+
emitDiagnostic2(diagnostics, {
|
|
8285
|
+
type: isArtifactInvalid ? "replay_governance_artifact_invalid" : "replay_governance_attachment_failed",
|
|
8286
|
+
session_id: sessionId,
|
|
8287
|
+
details: approvedRuntimeInitError.message
|
|
8288
|
+
});
|
|
8289
|
+
emitDiagnostic2(diagnostics, {
|
|
8290
|
+
type: "replay_compile_error",
|
|
8291
|
+
details: approvedRuntimeInitError.message
|
|
8292
|
+
});
|
|
8293
|
+
});
|
|
8294
|
+
await approvedRuntimeInitPromise;
|
|
8295
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8296
|
+
return approvedRuntimeSession;
|
|
8297
|
+
}
|
|
8298
|
+
async function invokeApprovedRuntimeCreate(args) {
|
|
8299
|
+
const runtimeSession = await ensureApprovedRuntimeSession();
|
|
8300
|
+
if (provider === "openai") {
|
|
8301
|
+
return runtimeSession.client.chat.completions.create(...args);
|
|
8302
|
+
}
|
|
8303
|
+
return runtimeSession.client.messages.create(...args);
|
|
8304
|
+
}
|
|
8305
|
+
const tools = opts.tools ? new Proxy(fallbackTools, {
|
|
8306
|
+
get(_target, prop) {
|
|
8307
|
+
if (typeof prop !== "string") return void 0;
|
|
8308
|
+
if (approvedRuntimeSession?.tools[prop]) {
|
|
8309
|
+
return approvedRuntimeSession.tools[prop];
|
|
8310
|
+
}
|
|
8311
|
+
return fallbackTools[prop];
|
|
8312
|
+
},
|
|
8313
|
+
has(_target, prop) {
|
|
8314
|
+
if (typeof prop !== "string") return false;
|
|
8315
|
+
return Boolean(approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]);
|
|
8316
|
+
},
|
|
8317
|
+
ownKeys() {
|
|
8318
|
+
const keys = /* @__PURE__ */ new Set([
|
|
8319
|
+
...Reflect.ownKeys(fallbackTools),
|
|
8320
|
+
...Reflect.ownKeys(approvedRuntimeSession?.tools ?? {})
|
|
8321
|
+
]);
|
|
8322
|
+
return Array.from(keys);
|
|
8323
|
+
},
|
|
8324
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
8325
|
+
if (typeof prop !== "string") return void 0;
|
|
8326
|
+
if (approvedRuntimeSession?.tools[prop] || fallbackTools[prop]) {
|
|
8327
|
+
return {
|
|
8328
|
+
configurable: true,
|
|
8329
|
+
enumerable: true,
|
|
8330
|
+
writable: false,
|
|
8331
|
+
value: approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]
|
|
8332
|
+
};
|
|
8333
|
+
}
|
|
8334
|
+
return void 0;
|
|
8335
|
+
}
|
|
8336
|
+
}) : {};
|
|
8024
8337
|
const patchedCreate = async function(...args) {
|
|
8025
8338
|
if (!planFetchDone && planFetchPromise) {
|
|
8026
8339
|
await planFetchPromise;
|
|
8027
8340
|
}
|
|
8028
|
-
|
|
8029
|
-
|
|
8341
|
+
if (planFetchError) {
|
|
8342
|
+
const artifactBroken = planFetchErrorCode === "APPROVED_ARTIFACT_INVALID";
|
|
8343
|
+
const requiresEnforcement = observeProtectionLevel !== "monitor";
|
|
8344
|
+
if (artifactBroken || requiresEnforcement) {
|
|
8345
|
+
throw new ReplayConfigError(
|
|
8346
|
+
"governance_unavailable",
|
|
8347
|
+
`Governance plan fetch failed (fail-closed): ${planFetchError}`
|
|
8348
|
+
);
|
|
8349
|
+
}
|
|
8350
|
+
}
|
|
8351
|
+
if (hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8352
|
+
return invokeApprovedRuntimeCreate(args);
|
|
8030
8353
|
}
|
|
8031
8354
|
const result = await originalCreate.apply(this, args);
|
|
8032
8355
|
try {
|
|
@@ -8055,40 +8378,81 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
8055
8378
|
setReplayAttached(client);
|
|
8056
8379
|
return {
|
|
8057
8380
|
client,
|
|
8058
|
-
flush: () => captureBuffer.flush(),
|
|
8381
|
+
flush: () => approvedRuntimeSession ? approvedRuntimeSession.flush() : captureBuffer.flush(),
|
|
8059
8382
|
restore() {
|
|
8060
8383
|
terminal[terminalInfo.methodName] = originalCreate;
|
|
8384
|
+
approvedRuntimeSession?.restore();
|
|
8385
|
+
clearReplayAttached(client);
|
|
8061
8386
|
},
|
|
8062
8387
|
kill() {
|
|
8388
|
+
approvedRuntimeSession?.kill();
|
|
8063
8389
|
},
|
|
8064
|
-
getHealth: () =>
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8390
|
+
getHealth: () => {
|
|
8391
|
+
if (approvedRuntimeSession) {
|
|
8392
|
+
const inner = approvedRuntimeSession.getHealth();
|
|
8393
|
+
return { ...inner, governanceAttachment: "attached" };
|
|
8394
|
+
}
|
|
8395
|
+
let governanceAttachment;
|
|
8396
|
+
let status;
|
|
8397
|
+
let authorityState;
|
|
8398
|
+
let totalErrors = 0;
|
|
8399
|
+
if (!planFetchDone) {
|
|
8400
|
+
governanceAttachment = "pending";
|
|
8401
|
+
status = "healthy";
|
|
8402
|
+
authorityState = "advisory";
|
|
8403
|
+
} else if (planFetchError) {
|
|
8404
|
+
governanceAttachment = "fetch_failed";
|
|
8405
|
+
status = "degraded";
|
|
8406
|
+
authorityState = "inactive";
|
|
8407
|
+
totalErrors = 1;
|
|
8408
|
+
} else if (approvedRuntimeInitError) {
|
|
8409
|
+
const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
|
|
8410
|
+
governanceAttachment = isArtifactInvalid ? "artifact_invalid" : "attachment_failed";
|
|
8411
|
+
status = "degraded";
|
|
8412
|
+
authorityState = "inactive";
|
|
8413
|
+
totalErrors = 1;
|
|
8414
|
+
} else if (!hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8415
|
+
governanceAttachment = "no_plan";
|
|
8416
|
+
status = "healthy";
|
|
8417
|
+
authorityState = "advisory";
|
|
8418
|
+
} else {
|
|
8419
|
+
governanceAttachment = "pending";
|
|
8420
|
+
status = "healthy";
|
|
8421
|
+
authorityState = "advisory";
|
|
8422
|
+
}
|
|
8423
|
+
return {
|
|
8424
|
+
status,
|
|
8425
|
+
authorityState,
|
|
8426
|
+
protectionLevel: observeProtectionLevel,
|
|
8427
|
+
durability: "inactive",
|
|
8428
|
+
tier: "compat",
|
|
8429
|
+
compatEnforcement: "protective",
|
|
8430
|
+
cluster_detected: false,
|
|
8431
|
+
bypass_detected: false,
|
|
8432
|
+
totalSteps: 0,
|
|
8433
|
+
totalBlocks: 0,
|
|
8434
|
+
totalErrors,
|
|
8435
|
+
killed: false,
|
|
8436
|
+
shadowEvaluations: 0,
|
|
8437
|
+
governanceAttachment
|
|
8438
|
+
};
|
|
8439
|
+
},
|
|
8440
|
+
getState: () => approvedRuntimeSession ? approvedRuntimeSession.getState() : EMPTY_STATE_SNAPSHOT,
|
|
8441
|
+
getLastNarrowing: () => approvedRuntimeSession ? approvedRuntimeSession.getLastNarrowing() : null,
|
|
8442
|
+
getLastShadowDelta: () => approvedRuntimeSession ? approvedRuntimeSession.getLastShadowDelta() : null,
|
|
8443
|
+
getLastTrace: () => approvedRuntimeSession ? approvedRuntimeSession.getLastTrace() : null,
|
|
8444
|
+
narrow(...args) {
|
|
8445
|
+
approvedRuntimeSession?.narrow(...args);
|
|
8084
8446
|
},
|
|
8085
8447
|
widen() {
|
|
8448
|
+
approvedRuntimeSession?.widen();
|
|
8086
8449
|
},
|
|
8087
|
-
addLabel() {
|
|
8450
|
+
addLabel(label) {
|
|
8451
|
+
approvedRuntimeSession?.addLabel(label);
|
|
8088
8452
|
},
|
|
8089
|
-
tools
|
|
8090
|
-
getWorkflowState: () => Promise.resolve(null),
|
|
8091
|
-
handoff: () => Promise.resolve(null)
|
|
8453
|
+
tools,
|
|
8454
|
+
getWorkflowState: () => approvedRuntimeSession ? approvedRuntimeSession.getWorkflowState() : Promise.resolve(null),
|
|
8455
|
+
handoff: (offer) => approvedRuntimeSession ? approvedRuntimeSession.handoff(offer) : Promise.resolve(null)
|
|
8092
8456
|
};
|
|
8093
8457
|
}
|
|
8094
8458
|
function toNarrowingSnapshot(result) {
|
|
@@ -8265,6 +8629,9 @@ function determineProtectionLevel(mode, tools, contracts, apiKey) {
|
|
|
8265
8629
|
const allWrapped = stateBearingTools.every((c) => wrappedTools.has(c.tool));
|
|
8266
8630
|
return allWrapped ? "govern" : "protect";
|
|
8267
8631
|
}
|
|
8632
|
+
function determineRuntimeFreeProtectionLevel(mode) {
|
|
8633
|
+
return mode === "enforce" ? "protect" : "monitor";
|
|
8634
|
+
}
|
|
8268
8635
|
function isStateBearing(contract) {
|
|
8269
8636
|
if (contract.commit_requirement != null && contract.commit_requirement !== "none") return true;
|
|
8270
8637
|
if (contract.transitions != null) return true;
|
package/dist/index.d.cts
CHANGED
|
@@ -699,6 +699,11 @@ type ReplaySession<T> = {
|
|
|
699
699
|
*/
|
|
700
700
|
handoff: (offer: HandoffOfferInput$1) => Promise<HandoffOfferResult$1 | null>;
|
|
701
701
|
};
|
|
702
|
+
/**
|
|
703
|
+
* Governance attachment state for zero-config governance sessions.
|
|
704
|
+
* @see replay.ts § createGovernanceSession
|
|
705
|
+
*/
|
|
706
|
+
type GovernanceAttachmentState = "pending" | "no_plan" | "attached" | "artifact_invalid" | "attachment_failed" | "fetch_failed";
|
|
702
707
|
/** @see specs/runtime-replay.md § ReplayHealthSnapshot */
|
|
703
708
|
type ReplayHealthSnapshot = {
|
|
704
709
|
status: "healthy" | "degraded" | "inactive";
|
|
@@ -716,6 +721,8 @@ type ReplayHealthSnapshot = {
|
|
|
716
721
|
killed: boolean;
|
|
717
722
|
/** Number of shadow-mode evaluations performed (always 0 in enforce/log-only). */
|
|
718
723
|
shadowEvaluations: number;
|
|
724
|
+
/** Governance attachment state. Only present for zero-config governance sessions. */
|
|
725
|
+
governanceAttachment?: GovernanceAttachmentState;
|
|
719
726
|
};
|
|
720
727
|
/**
|
|
721
728
|
* Public, redacted, JSON-serializable snapshot of session state.
|
|
@@ -1031,6 +1038,26 @@ type ReplayDiagnosticEvent = {
|
|
|
1031
1038
|
tool?: string;
|
|
1032
1039
|
phase?: string;
|
|
1033
1040
|
suggestion?: string;
|
|
1041
|
+
} | {
|
|
1042
|
+
type: "replay_governance_attached";
|
|
1043
|
+
session_id: string;
|
|
1044
|
+
environment: string;
|
|
1045
|
+
} | {
|
|
1046
|
+
type: "replay_governance_no_plan";
|
|
1047
|
+
session_id: string;
|
|
1048
|
+
environment: string;
|
|
1049
|
+
} | {
|
|
1050
|
+
type: "replay_governance_artifact_invalid";
|
|
1051
|
+
session_id: string;
|
|
1052
|
+
details: string;
|
|
1053
|
+
} | {
|
|
1054
|
+
type: "replay_governance_attachment_failed";
|
|
1055
|
+
session_id: string;
|
|
1056
|
+
details: string;
|
|
1057
|
+
} | {
|
|
1058
|
+
type: "replay_governance_fetch_failed";
|
|
1059
|
+
session_id: string;
|
|
1060
|
+
details: string;
|
|
1034
1061
|
};
|
|
1035
1062
|
/**
|
|
1036
1063
|
* Workflow state snapshot returned by `session.getWorkflowState()`.
|
|
@@ -1113,9 +1140,9 @@ declare class ReplayKillError extends Error {
|
|
|
1113
1140
|
* @see specs/replay-v1.md § Config errors (fail-closed)
|
|
1114
1141
|
*/
|
|
1115
1142
|
declare class ReplayConfigError extends ReplayConfigurationError {
|
|
1116
|
-
readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible";
|
|
1143
|
+
readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable";
|
|
1117
1144
|
readonly details: string;
|
|
1118
|
-
constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible", details: string);
|
|
1145
|
+
constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable", details: string);
|
|
1119
1146
|
}
|
|
1120
1147
|
|
|
1121
1148
|
/**
|
|
@@ -1242,7 +1269,7 @@ type ReceiptInput = {
|
|
|
1242
1269
|
executorId?: string | null;
|
|
1243
1270
|
toolName: string;
|
|
1244
1271
|
argumentsHash: string;
|
|
1245
|
-
status: "SUCCEEDED" | "FAILED" | "DISCARDED";
|
|
1272
|
+
status: "SUCCEEDED" | "FAILED" | "DISCARDED" | "AMBIGUOUS";
|
|
1246
1273
|
outputHash?: string | null;
|
|
1247
1274
|
outputExtract?: Record<string, unknown> | null;
|
|
1248
1275
|
resourceValues?: Record<string, unknown> | null;
|
|
@@ -1255,6 +1282,8 @@ type ReceiptResult = {
|
|
|
1255
1282
|
commitState: "committed" | "uncommitted";
|
|
1256
1283
|
stateAdvanced: boolean;
|
|
1257
1284
|
stateVersion: number;
|
|
1285
|
+
executionState: "outcome_recorded" | "ambiguous";
|
|
1286
|
+
pendingStatus: "resolved" | "pending" | "ambiguous";
|
|
1258
1287
|
};
|
|
1259
1288
|
type ToolFilterInput = {
|
|
1260
1289
|
sessionId: string;
|
|
@@ -1366,4 +1395,4 @@ declare class RuntimeClient {
|
|
|
1366
1395
|
private recordFailure;
|
|
1367
1396
|
}
|
|
1368
1397
|
|
|
1369
|
-
export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
|
|
1398
|
+
export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type GovernanceAttachmentState, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
|
package/dist/index.d.ts
CHANGED
|
@@ -699,6 +699,11 @@ type ReplaySession<T> = {
|
|
|
699
699
|
*/
|
|
700
700
|
handoff: (offer: HandoffOfferInput$1) => Promise<HandoffOfferResult$1 | null>;
|
|
701
701
|
};
|
|
702
|
+
/**
|
|
703
|
+
* Governance attachment state for zero-config governance sessions.
|
|
704
|
+
* @see replay.ts § createGovernanceSession
|
|
705
|
+
*/
|
|
706
|
+
type GovernanceAttachmentState = "pending" | "no_plan" | "attached" | "artifact_invalid" | "attachment_failed" | "fetch_failed";
|
|
702
707
|
/** @see specs/runtime-replay.md § ReplayHealthSnapshot */
|
|
703
708
|
type ReplayHealthSnapshot = {
|
|
704
709
|
status: "healthy" | "degraded" | "inactive";
|
|
@@ -716,6 +721,8 @@ type ReplayHealthSnapshot = {
|
|
|
716
721
|
killed: boolean;
|
|
717
722
|
/** Number of shadow-mode evaluations performed (always 0 in enforce/log-only). */
|
|
718
723
|
shadowEvaluations: number;
|
|
724
|
+
/** Governance attachment state. Only present for zero-config governance sessions. */
|
|
725
|
+
governanceAttachment?: GovernanceAttachmentState;
|
|
719
726
|
};
|
|
720
727
|
/**
|
|
721
728
|
* Public, redacted, JSON-serializable snapshot of session state.
|
|
@@ -1031,6 +1038,26 @@ type ReplayDiagnosticEvent = {
|
|
|
1031
1038
|
tool?: string;
|
|
1032
1039
|
phase?: string;
|
|
1033
1040
|
suggestion?: string;
|
|
1041
|
+
} | {
|
|
1042
|
+
type: "replay_governance_attached";
|
|
1043
|
+
session_id: string;
|
|
1044
|
+
environment: string;
|
|
1045
|
+
} | {
|
|
1046
|
+
type: "replay_governance_no_plan";
|
|
1047
|
+
session_id: string;
|
|
1048
|
+
environment: string;
|
|
1049
|
+
} | {
|
|
1050
|
+
type: "replay_governance_artifact_invalid";
|
|
1051
|
+
session_id: string;
|
|
1052
|
+
details: string;
|
|
1053
|
+
} | {
|
|
1054
|
+
type: "replay_governance_attachment_failed";
|
|
1055
|
+
session_id: string;
|
|
1056
|
+
details: string;
|
|
1057
|
+
} | {
|
|
1058
|
+
type: "replay_governance_fetch_failed";
|
|
1059
|
+
session_id: string;
|
|
1060
|
+
details: string;
|
|
1034
1061
|
};
|
|
1035
1062
|
/**
|
|
1036
1063
|
* Workflow state snapshot returned by `session.getWorkflowState()`.
|
|
@@ -1113,9 +1140,9 @@ declare class ReplayKillError extends Error {
|
|
|
1113
1140
|
* @see specs/replay-v1.md § Config errors (fail-closed)
|
|
1114
1141
|
*/
|
|
1115
1142
|
declare class ReplayConfigError extends ReplayConfigurationError {
|
|
1116
|
-
readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible";
|
|
1143
|
+
readonly condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable";
|
|
1117
1144
|
readonly details: string;
|
|
1118
|
-
constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible", details: string);
|
|
1145
|
+
constructor(condition: "policy_without_principal" | "constraints_without_wrapper" | "compilation_failed" | "provider_incompatible" | "governance_unavailable", details: string);
|
|
1119
1146
|
}
|
|
1120
1147
|
|
|
1121
1148
|
/**
|
|
@@ -1242,7 +1269,7 @@ type ReceiptInput = {
|
|
|
1242
1269
|
executorId?: string | null;
|
|
1243
1270
|
toolName: string;
|
|
1244
1271
|
argumentsHash: string;
|
|
1245
|
-
status: "SUCCEEDED" | "FAILED" | "DISCARDED";
|
|
1272
|
+
status: "SUCCEEDED" | "FAILED" | "DISCARDED" | "AMBIGUOUS";
|
|
1246
1273
|
outputHash?: string | null;
|
|
1247
1274
|
outputExtract?: Record<string, unknown> | null;
|
|
1248
1275
|
resourceValues?: Record<string, unknown> | null;
|
|
@@ -1255,6 +1282,8 @@ type ReceiptResult = {
|
|
|
1255
1282
|
commitState: "committed" | "uncommitted";
|
|
1256
1283
|
stateAdvanced: boolean;
|
|
1257
1284
|
stateVersion: number;
|
|
1285
|
+
executionState: "outcome_recorded" | "ambiguous";
|
|
1286
|
+
pendingStatus: "resolved" | "pending" | "ambiguous";
|
|
1258
1287
|
};
|
|
1259
1288
|
type ToolFilterInput = {
|
|
1260
1289
|
sessionId: string;
|
|
@@ -1366,4 +1395,4 @@ declare class RuntimeClient {
|
|
|
1366
1395
|
private recordFailure;
|
|
1367
1396
|
}
|
|
1368
1397
|
|
|
1369
|
-
export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
|
|
1398
|
+
export { type AggregateState, type BlockReason, type BlockedToolCall, type BoundValue, type CircuitBreakerResult, type CompareAndSetResult, type CompletedStep, type CompletedStepSnapshot, type CompletedToolCall, type CompletedToolCallSnapshot, type ConstraintFailure, type ConstraintVerdict, type ContractFailure, type CrossStepCaptureResult, type CrossStepFailure, type CrossStepResult, type DecisionOutcome, type DecisionTrace, type FlushResult, type GateMode, type GovernanceAttachmentState, type LoopDetectionResult, MemoryStore, type NarrowRemovalReason, type NarrowResult, type NarrowedTool, type ObserveActivationReasonCode, type ObserveDiagnosticEvent, type ObserveHandle, type ObserveHealthSnapshot, type ObserveOptions, type ObserveSessionState, type PendingEntry, type PhaseTransitionResult, type PolicyVerdict, type PreconditionEvidence, type ReplayCapture, ReplayConfigError, ReplayContractError, type ReplayDecision, type ReplayDiagnosticEvent, type ReplayHealthSnapshot, ReplayKillError, type ReplayMode, type ReplayOptions, type ReplaySession, type ReplayTiming, type ResponseMetadata, RuntimeClient, RuntimeClientError, type RuntimeClientHealth, type RuntimeClientOptions, type RuntimeSessionInit, type RuntimeSessionResult, type SessionState, type SessionStateSnapshot, type ShadowDelta, type Store, type ToolDefinition, type ToolExecutor, type TraceContext, type TraceEntry, type TraceStage, type ValidationResult, type WrappedExecutorResult, type WrappedToolExecutor, createRuntimeClient, observe, prepareContracts, replay, validate };
|
package/dist/index.js
CHANGED
|
@@ -5205,7 +5205,9 @@ var RuntimeClient = class {
|
|
|
5205
5205
|
accepted: r.accepted,
|
|
5206
5206
|
commitState: r.commit_state,
|
|
5207
5207
|
stateAdvanced: r.state_advanced,
|
|
5208
|
-
stateVersion: r.state_version
|
|
5208
|
+
stateVersion: r.state_version,
|
|
5209
|
+
executionState: r.execution_state ?? "outcome_recorded",
|
|
5210
|
+
pendingStatus: r.pending_status ?? (r.state_advanced ? "resolved" : "pending")
|
|
5209
5211
|
};
|
|
5210
5212
|
}
|
|
5211
5213
|
async setToolFilter(input) {
|
|
@@ -5466,6 +5468,7 @@ var DEFAULT_AGENT2 = "default";
|
|
|
5466
5468
|
var DEFAULT_MAX_UNGUARDED_CALLS = 3;
|
|
5467
5469
|
function replay(client, opts = {}) {
|
|
5468
5470
|
assertSupportedNodeRuntime();
|
|
5471
|
+
const internalOpts = opts;
|
|
5469
5472
|
const sessionId = opts.sessionId ?? generateSessionId2();
|
|
5470
5473
|
const agent = typeof opts.agent === "string" && opts.agent.length > 0 ? opts.agent : DEFAULT_AGENT2;
|
|
5471
5474
|
const mode = opts.mode ?? "enforce";
|
|
@@ -5487,17 +5490,20 @@ function replay(client, opts = {}) {
|
|
|
5487
5490
|
return createInactiveSession(client, sessionId, "Client already has an active observe() or replay() attachment");
|
|
5488
5491
|
}
|
|
5489
5492
|
let contracts;
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5493
|
+
if (internalOpts.__preparedContracts && internalOpts.__preparedContracts.length > 0) {
|
|
5494
|
+
contracts = internalOpts.__preparedContracts;
|
|
5495
|
+
} else {
|
|
5496
|
+
try {
|
|
5497
|
+
contracts = resolveContracts(opts);
|
|
5498
|
+
} catch (err) {
|
|
5499
|
+
const apiKeyForGov = resolveApiKey2(opts);
|
|
5500
|
+
if (apiKeyForGov && !opts.contracts && !opts.contractsDir) {
|
|
5501
|
+
return createGovernanceSession(client, sessionId, agent, provider, apiKeyForGov, opts, diagnostics);
|
|
5502
|
+
}
|
|
5503
|
+
const detail = err instanceof Error ? err.message : "Failed to load contracts";
|
|
5504
|
+
emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
|
|
5505
|
+
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5497
5506
|
}
|
|
5498
|
-
const detail = err instanceof Error ? err.message : "Failed to load contracts";
|
|
5499
|
-
emitDiagnostic2(diagnostics, { type: "replay_compile_error", details: detail });
|
|
5500
|
-
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5501
5507
|
}
|
|
5502
5508
|
const configError = validateConfig(contracts, opts);
|
|
5503
5509
|
if (configError) {
|
|
@@ -5524,20 +5530,22 @@ function replay(client, opts = {}) {
|
|
|
5524
5530
|
} else if (sessionYaml && opts.providerConstraints && !sessionYaml.provider_constraints) {
|
|
5525
5531
|
sessionYaml = { ...sessionYaml, provider_constraints: opts.providerConstraints };
|
|
5526
5532
|
}
|
|
5527
|
-
let compiledSession = null;
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5533
|
+
let compiledSession = internalOpts.__compiledSession ?? null;
|
|
5534
|
+
if (!compiledSession) {
|
|
5535
|
+
try {
|
|
5536
|
+
compiledSession = compileSession(contracts, sessionYaml, {
|
|
5537
|
+
principal: opts.principal,
|
|
5538
|
+
tools: opts.tools ? new Map(Object.entries(opts.tools)) : void 0
|
|
5539
|
+
});
|
|
5540
|
+
} catch (err) {
|
|
5541
|
+
const detail = `Session compilation failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
5542
|
+
emitDiagnostic2(diagnostics, {
|
|
5543
|
+
type: "replay_compile_error",
|
|
5544
|
+
details: detail
|
|
5545
|
+
});
|
|
5546
|
+
if (discoveredSessionYaml) {
|
|
5547
|
+
return createBlockingInactiveSession(client, sessionId, detail);
|
|
5548
|
+
}
|
|
5541
5549
|
}
|
|
5542
5550
|
}
|
|
5543
5551
|
if (compiledSession?.warnings && compiledSession.warnings.length > 0) {
|
|
@@ -5604,7 +5612,7 @@ function replay(client, opts = {}) {
|
|
|
5604
5612
|
return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
|
|
5605
5613
|
}
|
|
5606
5614
|
const apiKey = resolveApiKey2(opts);
|
|
5607
|
-
const protectionLevel = determineProtectionLevel(mode, opts.tools, contracts, apiKey);
|
|
5615
|
+
const protectionLevel = internalOpts.__disableRuntimeControlPlane ? determineRuntimeFreeProtectionLevel(mode) : determineProtectionLevel(mode, opts.tools, contracts, apiKey);
|
|
5608
5616
|
const maxUnguardedCalls = opts.maxUnguardedCalls ?? DEFAULT_MAX_UNGUARDED_CALLS;
|
|
5609
5617
|
const narrowingFeedback = opts.narrowingFeedback ?? "silent";
|
|
5610
5618
|
let runtimeClient = null;
|
|
@@ -7963,6 +7971,185 @@ function createBlockingInactiveSession(client, sessionId, detail, configError) {
|
|
|
7963
7971
|
handoff: () => Promise.resolve(null)
|
|
7964
7972
|
};
|
|
7965
7973
|
}
|
|
7974
|
+
function createPreparedContractsFromCompiledSession(compiledSession) {
|
|
7975
|
+
return Array.from(compiledSession.perToolContracts.values()).map((contract) => ({
|
|
7976
|
+
...contract,
|
|
7977
|
+
contract_file: contract.tool
|
|
7978
|
+
}));
|
|
7979
|
+
}
|
|
7980
|
+
function requireArtifactRecord(value, field) {
|
|
7981
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7982
|
+
throw new ReplayConfigError(
|
|
7983
|
+
"compilation_failed",
|
|
7984
|
+
`Approved governance artifact has invalid ${field}`
|
|
7985
|
+
);
|
|
7986
|
+
}
|
|
7987
|
+
return value;
|
|
7988
|
+
}
|
|
7989
|
+
function requireArtifactStringArray(value, field) {
|
|
7990
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
7991
|
+
throw new ReplayConfigError(
|
|
7992
|
+
"compilation_failed",
|
|
7993
|
+
`Approved governance artifact has invalid ${field}`
|
|
7994
|
+
);
|
|
7995
|
+
}
|
|
7996
|
+
return value;
|
|
7997
|
+
}
|
|
7998
|
+
function requireArtifactEntryArray(value, field) {
|
|
7999
|
+
if (!Array.isArray(value)) {
|
|
8000
|
+
throw new ReplayConfigError(
|
|
8001
|
+
"compilation_failed",
|
|
8002
|
+
`Approved governance artifact has invalid ${field}`
|
|
8003
|
+
);
|
|
8004
|
+
}
|
|
8005
|
+
return value.map((entry) => {
|
|
8006
|
+
if (!Array.isArray(entry) || entry.length !== 2 || typeof entry[0] !== "string") {
|
|
8007
|
+
throw new ReplayConfigError(
|
|
8008
|
+
"compilation_failed",
|
|
8009
|
+
`Approved governance artifact has invalid ${field}`
|
|
8010
|
+
);
|
|
8011
|
+
}
|
|
8012
|
+
return [entry[0], entry[1]];
|
|
8013
|
+
});
|
|
8014
|
+
}
|
|
8015
|
+
function hydrateStringArrayMap(value, field) {
|
|
8016
|
+
return new Map(
|
|
8017
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
|
|
8018
|
+
key,
|
|
8019
|
+
requireArtifactStringArray(entryValue, `${field}.${key}`)
|
|
8020
|
+
])
|
|
8021
|
+
);
|
|
8022
|
+
}
|
|
8023
|
+
function hydrateContractMap(value, field) {
|
|
8024
|
+
return new Map(
|
|
8025
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => [
|
|
8026
|
+
key,
|
|
8027
|
+
requireArtifactRecord(entryValue, `${field}.${key}`)
|
|
8028
|
+
])
|
|
8029
|
+
);
|
|
8030
|
+
}
|
|
8031
|
+
function hydrateExecutionConstraintMap(value, field) {
|
|
8032
|
+
return new Map(
|
|
8033
|
+
requireArtifactEntryArray(value, field).map(([key, entryValue]) => {
|
|
8034
|
+
if (!Array.isArray(entryValue)) {
|
|
8035
|
+
throw new ReplayConfigError(
|
|
8036
|
+
"compilation_failed",
|
|
8037
|
+
`Approved governance artifact has invalid ${field}.${key}`
|
|
8038
|
+
);
|
|
8039
|
+
}
|
|
8040
|
+
return [key, entryValue];
|
|
8041
|
+
})
|
|
8042
|
+
);
|
|
8043
|
+
}
|
|
8044
|
+
function hydrateNestedStringMap(value, field) {
|
|
8045
|
+
return new Map(
|
|
8046
|
+
requireArtifactEntryArray(value, field).map(([outerKey, innerValue]) => {
|
|
8047
|
+
const nested = new Map(
|
|
8048
|
+
requireArtifactEntryArray(innerValue, `${field}.${outerKey}`).map(([innerKey, nestedValue]) => {
|
|
8049
|
+
if (typeof nestedValue !== "string") {
|
|
8050
|
+
throw new ReplayConfigError(
|
|
8051
|
+
"compilation_failed",
|
|
8052
|
+
`Approved governance artifact has invalid ${field}.${outerKey}.${innerKey}`
|
|
8053
|
+
);
|
|
8054
|
+
}
|
|
8055
|
+
return [innerKey, nestedValue];
|
|
8056
|
+
})
|
|
8057
|
+
);
|
|
8058
|
+
return [outerKey, nested];
|
|
8059
|
+
})
|
|
8060
|
+
);
|
|
8061
|
+
}
|
|
8062
|
+
function hydratePolicyProgram(value) {
|
|
8063
|
+
if (value == null) return null;
|
|
8064
|
+
const policyProgram = requireArtifactRecord(value, "policyProgram");
|
|
8065
|
+
if (typeof policyProgram.defaultDeny !== "boolean" || !Array.isArray(policyProgram.sessionRules)) {
|
|
8066
|
+
throw new ReplayConfigError(
|
|
8067
|
+
"compilation_failed",
|
|
8068
|
+
"Approved governance artifact has invalid policyProgram"
|
|
8069
|
+
);
|
|
8070
|
+
}
|
|
8071
|
+
return {
|
|
8072
|
+
defaultDeny: policyProgram.defaultDeny,
|
|
8073
|
+
sessionRules: policyProgram.sessionRules,
|
|
8074
|
+
perToolRules: new Map(
|
|
8075
|
+
requireArtifactEntryArray(policyProgram.perToolRules ?? [], "policyProgram.perToolRules").map(
|
|
8076
|
+
([toolName, ruleValue]) => [toolName, requireArtifactRecord(ruleValue, `policyProgram.perToolRules.${toolName}`)]
|
|
8077
|
+
)
|
|
8078
|
+
)
|
|
8079
|
+
};
|
|
8080
|
+
}
|
|
8081
|
+
function rehydrateCompiledSessionArtifact(artifact, expectedHash) {
|
|
8082
|
+
const record = requireArtifactRecord(artifact, "compiled_session");
|
|
8083
|
+
if (typeof record.agent !== "string" || typeof record.schemaVersion !== "string") {
|
|
8084
|
+
throw new ReplayConfigError(
|
|
8085
|
+
"compilation_failed",
|
|
8086
|
+
"Approved governance artifact is missing required session metadata"
|
|
8087
|
+
);
|
|
8088
|
+
}
|
|
8089
|
+
if (record.phases != null && !Array.isArray(record.phases)) {
|
|
8090
|
+
throw new ReplayConfigError(
|
|
8091
|
+
"compilation_failed",
|
|
8092
|
+
"Approved governance artifact has invalid phases"
|
|
8093
|
+
);
|
|
8094
|
+
}
|
|
8095
|
+
if (!Array.isArray(record.contractHashes) || record.contractHashes.some((hash) => typeof hash !== "string")) {
|
|
8096
|
+
throw new ReplayConfigError(
|
|
8097
|
+
"compilation_failed",
|
|
8098
|
+
"Approved governance artifact has invalid contractHashes"
|
|
8099
|
+
);
|
|
8100
|
+
}
|
|
8101
|
+
const compiledSession = {
|
|
8102
|
+
agent: record.agent,
|
|
8103
|
+
schemaVersion: record.schemaVersion,
|
|
8104
|
+
phases: record.phases ?? null,
|
|
8105
|
+
transitions: hydrateStringArrayMap(record.transitions ?? [], "transitions"),
|
|
8106
|
+
sessionLimits: record.sessionLimits ?? {},
|
|
8107
|
+
perToolContracts: hydrateContractMap(record.perToolContracts ?? [], "perToolContracts"),
|
|
8108
|
+
riskDefaults: requireArtifactRecord(record.riskDefaults ?? {}, "riskDefaults"),
|
|
8109
|
+
providerConstraints: record.providerConstraints ?? null,
|
|
8110
|
+
contractHashes: record.contractHashes,
|
|
8111
|
+
compiledHash: "",
|
|
8112
|
+
principal: null,
|
|
8113
|
+
policyProgram: hydratePolicyProgram(record.policyProgram),
|
|
8114
|
+
executionConstraints: hydrateExecutionConstraintMap(record.executionConstraints ?? [], "executionConstraints"),
|
|
8115
|
+
toolExecutors: null,
|
|
8116
|
+
resources: hydrateNestedStringMap(record.resources ?? [], "resources"),
|
|
8117
|
+
warnings: [],
|
|
8118
|
+
graphDiagnostics: [],
|
|
8119
|
+
schemaDerivedDiagnostics: [],
|
|
8120
|
+
aggregates: Array.isArray(record.aggregates) ? record.aggregates : [],
|
|
8121
|
+
envelopes: Array.isArray(record.envelopes) ? record.envelopes : [],
|
|
8122
|
+
labelGates: Array.isArray(record.labelGates) ? record.labelGates : [],
|
|
8123
|
+
checkpoints: Array.isArray(record.checkpoints) ? record.checkpoints : []
|
|
8124
|
+
};
|
|
8125
|
+
const serialized = serializeCompiledSession(compiledSession);
|
|
8126
|
+
const computedHash = crypto5.createHash("sha256").update(serialized).digest("hex");
|
|
8127
|
+
compiledSession.compiledHash = computedHash;
|
|
8128
|
+
if (expectedHash && expectedHash !== computedHash) {
|
|
8129
|
+
throw new ReplayConfigError(
|
|
8130
|
+
"compilation_failed",
|
|
8131
|
+
`Approved governance artifact hash mismatch: expected ${expectedHash}, got ${computedHash}`
|
|
8132
|
+
);
|
|
8133
|
+
}
|
|
8134
|
+
return compiledSession;
|
|
8135
|
+
}
|
|
8136
|
+
function createDetachedProviderClient(provider, terminal, originalCreate) {
|
|
8137
|
+
const boundCreate = (...args) => originalCreate.apply(terminal, args);
|
|
8138
|
+
if (provider === "openai") {
|
|
8139
|
+
return {
|
|
8140
|
+
chat: {
|
|
8141
|
+
completions: {
|
|
8142
|
+
create: boundCreate
|
|
8143
|
+
}
|
|
8144
|
+
}
|
|
8145
|
+
};
|
|
8146
|
+
}
|
|
8147
|
+
return {
|
|
8148
|
+
messages: {
|
|
8149
|
+
create: boundCreate
|
|
8150
|
+
}
|
|
8151
|
+
};
|
|
8152
|
+
}
|
|
7966
8153
|
function resolveGovernanceEnvironment(opts) {
|
|
7967
8154
|
if (opts.environment) return opts.environment;
|
|
7968
8155
|
const envVar = typeof process !== "undefined" ? process.env.REPLAYCI_ENVIRONMENT : void 0;
|
|
@@ -7985,7 +8172,7 @@ function governanceProtectionLevel(env) {
|
|
|
7985
8172
|
}
|
|
7986
8173
|
function createGovernanceSession(client, sessionId, agent, provider, apiKey, opts, diagnostics) {
|
|
7987
8174
|
const environment = resolveGovernanceEnvironment(opts);
|
|
7988
|
-
const
|
|
8175
|
+
const observeProtectionLevel = governanceProtectionLevel(environment);
|
|
7989
8176
|
const runtimeClient = new RuntimeClient({
|
|
7990
8177
|
apiKey,
|
|
7991
8178
|
apiUrl: opts.runtimeUrl
|
|
@@ -7994,13 +8181,22 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
7994
8181
|
let planFetchPromise = null;
|
|
7995
8182
|
let planFetchDone = false;
|
|
7996
8183
|
let planFetchError = null;
|
|
8184
|
+
let planFetchErrorCode = null;
|
|
8185
|
+
let approvedRuntimeSession = null;
|
|
8186
|
+
let approvedRuntimeInitPromise = null;
|
|
8187
|
+
let approvedRuntimeInitError = null;
|
|
7997
8188
|
planFetchPromise = runtimeClient.fetchGovernancePlan(agent, environment).then((result) => {
|
|
7998
8189
|
governancePlan = result;
|
|
7999
8190
|
planFetchDone = true;
|
|
8191
|
+
if (!hasApprovedGovernanceArtifact(result)) {
|
|
8192
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_no_plan", session_id: sessionId, environment });
|
|
8193
|
+
}
|
|
8000
8194
|
}).catch((err) => {
|
|
8001
8195
|
planFetchDone = true;
|
|
8002
8196
|
planFetchError = err instanceof Error ? err.message : String(err);
|
|
8197
|
+
planFetchErrorCode = err instanceof RuntimeClientError ? err.code : null;
|
|
8003
8198
|
governancePlan = null;
|
|
8199
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_fetch_failed", session_id: sessionId, details: planFetchError });
|
|
8004
8200
|
});
|
|
8005
8201
|
const captureBuffer = new CaptureBuffer({
|
|
8006
8202
|
apiKey,
|
|
@@ -8013,12 +8209,139 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
8013
8209
|
return createInactiveSession(client, sessionId, "Could not resolve terminal resource");
|
|
8014
8210
|
}
|
|
8015
8211
|
const { terminal, originalCreate } = terminalInfo;
|
|
8212
|
+
const fallbackTools = buildWrappedToolsMap(opts.tools, null);
|
|
8213
|
+
function hasApprovedGovernanceArtifact(plan) {
|
|
8214
|
+
return Boolean(
|
|
8215
|
+
plan && (plan.status === "approved" || plan.status === "enforcing")
|
|
8216
|
+
);
|
|
8217
|
+
}
|
|
8218
|
+
async function ensureApprovedRuntimeSession() {
|
|
8219
|
+
if (approvedRuntimeSession) return approvedRuntimeSession;
|
|
8220
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8221
|
+
if (approvedRuntimeInitPromise) {
|
|
8222
|
+
await approvedRuntimeInitPromise;
|
|
8223
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8224
|
+
return approvedRuntimeSession;
|
|
8225
|
+
}
|
|
8226
|
+
approvedRuntimeInitPromise = (async () => {
|
|
8227
|
+
if (!hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8228
|
+
throw new ReplayConfigError(
|
|
8229
|
+
"compilation_failed",
|
|
8230
|
+
"Approved governance artifact was not available for runtime enforcement"
|
|
8231
|
+
);
|
|
8232
|
+
}
|
|
8233
|
+
if (!governancePlan?.compiledSession) {
|
|
8234
|
+
throw new ReplayConfigError(
|
|
8235
|
+
"compilation_failed",
|
|
8236
|
+
"Approved governance plan is missing compiled_session"
|
|
8237
|
+
);
|
|
8238
|
+
}
|
|
8239
|
+
if (!governancePlan.compiledHash) {
|
|
8240
|
+
throw new ReplayConfigError(
|
|
8241
|
+
"compilation_failed",
|
|
8242
|
+
"Approved governance plan is missing compiled_hash"
|
|
8243
|
+
);
|
|
8244
|
+
}
|
|
8245
|
+
const compiledSession = rehydrateCompiledSessionArtifact(
|
|
8246
|
+
governancePlan.compiledSession,
|
|
8247
|
+
governancePlan.compiledHash
|
|
8248
|
+
);
|
|
8249
|
+
const preparedContracts = createPreparedContractsFromCompiledSession(compiledSession);
|
|
8250
|
+
const detachedClient = createDetachedProviderClient(
|
|
8251
|
+
provider,
|
|
8252
|
+
terminal,
|
|
8253
|
+
originalCreate
|
|
8254
|
+
);
|
|
8255
|
+
const approvedMode = environment === "development" ? "shadow" : "enforce";
|
|
8256
|
+
const approvedCompatEnforcement = environment === "staging" ? "advisory" : opts.compatEnforcement ?? "protective";
|
|
8257
|
+
approvedRuntimeSession = replay(detachedClient, {
|
|
8258
|
+
...opts,
|
|
8259
|
+
agent,
|
|
8260
|
+
sessionId,
|
|
8261
|
+
apiKey,
|
|
8262
|
+
mode: approvedMode,
|
|
8263
|
+
compatEnforcement: approvedCompatEnforcement,
|
|
8264
|
+
contracts: void 0,
|
|
8265
|
+
contractsDir: void 0,
|
|
8266
|
+
sessionYamlPath: void 0,
|
|
8267
|
+
environment: void 0,
|
|
8268
|
+
__preparedContracts: preparedContracts,
|
|
8269
|
+
__compiledSession: compiledSession,
|
|
8270
|
+
__disableRuntimeControlPlane: true
|
|
8271
|
+
});
|
|
8272
|
+
emitDiagnostic2(diagnostics, { type: "replay_governance_attached", session_id: sessionId, environment });
|
|
8273
|
+
})().catch((err) => {
|
|
8274
|
+
approvedRuntimeInitError = err instanceof Error ? err : new ReplayConfigError("compilation_failed", String(err));
|
|
8275
|
+
const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
|
|
8276
|
+
emitDiagnostic2(diagnostics, {
|
|
8277
|
+
type: isArtifactInvalid ? "replay_governance_artifact_invalid" : "replay_governance_attachment_failed",
|
|
8278
|
+
session_id: sessionId,
|
|
8279
|
+
details: approvedRuntimeInitError.message
|
|
8280
|
+
});
|
|
8281
|
+
emitDiagnostic2(diagnostics, {
|
|
8282
|
+
type: "replay_compile_error",
|
|
8283
|
+
details: approvedRuntimeInitError.message
|
|
8284
|
+
});
|
|
8285
|
+
});
|
|
8286
|
+
await approvedRuntimeInitPromise;
|
|
8287
|
+
if (approvedRuntimeInitError) throw approvedRuntimeInitError;
|
|
8288
|
+
return approvedRuntimeSession;
|
|
8289
|
+
}
|
|
8290
|
+
async function invokeApprovedRuntimeCreate(args) {
|
|
8291
|
+
const runtimeSession = await ensureApprovedRuntimeSession();
|
|
8292
|
+
if (provider === "openai") {
|
|
8293
|
+
return runtimeSession.client.chat.completions.create(...args);
|
|
8294
|
+
}
|
|
8295
|
+
return runtimeSession.client.messages.create(...args);
|
|
8296
|
+
}
|
|
8297
|
+
const tools = opts.tools ? new Proxy(fallbackTools, {
|
|
8298
|
+
get(_target, prop) {
|
|
8299
|
+
if (typeof prop !== "string") return void 0;
|
|
8300
|
+
if (approvedRuntimeSession?.tools[prop]) {
|
|
8301
|
+
return approvedRuntimeSession.tools[prop];
|
|
8302
|
+
}
|
|
8303
|
+
return fallbackTools[prop];
|
|
8304
|
+
},
|
|
8305
|
+
has(_target, prop) {
|
|
8306
|
+
if (typeof prop !== "string") return false;
|
|
8307
|
+
return Boolean(approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]);
|
|
8308
|
+
},
|
|
8309
|
+
ownKeys() {
|
|
8310
|
+
const keys = /* @__PURE__ */ new Set([
|
|
8311
|
+
...Reflect.ownKeys(fallbackTools),
|
|
8312
|
+
...Reflect.ownKeys(approvedRuntimeSession?.tools ?? {})
|
|
8313
|
+
]);
|
|
8314
|
+
return Array.from(keys);
|
|
8315
|
+
},
|
|
8316
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
8317
|
+
if (typeof prop !== "string") return void 0;
|
|
8318
|
+
if (approvedRuntimeSession?.tools[prop] || fallbackTools[prop]) {
|
|
8319
|
+
return {
|
|
8320
|
+
configurable: true,
|
|
8321
|
+
enumerable: true,
|
|
8322
|
+
writable: false,
|
|
8323
|
+
value: approvedRuntimeSession?.tools[prop] ?? fallbackTools[prop]
|
|
8324
|
+
};
|
|
8325
|
+
}
|
|
8326
|
+
return void 0;
|
|
8327
|
+
}
|
|
8328
|
+
}) : {};
|
|
8016
8329
|
const patchedCreate = async function(...args) {
|
|
8017
8330
|
if (!planFetchDone && planFetchPromise) {
|
|
8018
8331
|
await planFetchPromise;
|
|
8019
8332
|
}
|
|
8020
|
-
|
|
8021
|
-
|
|
8333
|
+
if (planFetchError) {
|
|
8334
|
+
const artifactBroken = planFetchErrorCode === "APPROVED_ARTIFACT_INVALID";
|
|
8335
|
+
const requiresEnforcement = observeProtectionLevel !== "monitor";
|
|
8336
|
+
if (artifactBroken || requiresEnforcement) {
|
|
8337
|
+
throw new ReplayConfigError(
|
|
8338
|
+
"governance_unavailable",
|
|
8339
|
+
`Governance plan fetch failed (fail-closed): ${planFetchError}`
|
|
8340
|
+
);
|
|
8341
|
+
}
|
|
8342
|
+
}
|
|
8343
|
+
if (hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8344
|
+
return invokeApprovedRuntimeCreate(args);
|
|
8022
8345
|
}
|
|
8023
8346
|
const result = await originalCreate.apply(this, args);
|
|
8024
8347
|
try {
|
|
@@ -8047,40 +8370,81 @@ function createGovernanceSession(client, sessionId, agent, provider, apiKey, opt
|
|
|
8047
8370
|
setReplayAttached(client);
|
|
8048
8371
|
return {
|
|
8049
8372
|
client,
|
|
8050
|
-
flush: () => captureBuffer.flush(),
|
|
8373
|
+
flush: () => approvedRuntimeSession ? approvedRuntimeSession.flush() : captureBuffer.flush(),
|
|
8051
8374
|
restore() {
|
|
8052
8375
|
terminal[terminalInfo.methodName] = originalCreate;
|
|
8376
|
+
approvedRuntimeSession?.restore();
|
|
8377
|
+
clearReplayAttached(client);
|
|
8053
8378
|
},
|
|
8054
8379
|
kill() {
|
|
8380
|
+
approvedRuntimeSession?.kill();
|
|
8055
8381
|
},
|
|
8056
|
-
getHealth: () =>
|
|
8057
|
-
|
|
8058
|
-
|
|
8059
|
-
|
|
8060
|
-
|
|
8061
|
-
|
|
8062
|
-
|
|
8063
|
-
|
|
8064
|
-
|
|
8065
|
-
|
|
8066
|
-
|
|
8067
|
-
|
|
8068
|
-
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8382
|
+
getHealth: () => {
|
|
8383
|
+
if (approvedRuntimeSession) {
|
|
8384
|
+
const inner = approvedRuntimeSession.getHealth();
|
|
8385
|
+
return { ...inner, governanceAttachment: "attached" };
|
|
8386
|
+
}
|
|
8387
|
+
let governanceAttachment;
|
|
8388
|
+
let status;
|
|
8389
|
+
let authorityState;
|
|
8390
|
+
let totalErrors = 0;
|
|
8391
|
+
if (!planFetchDone) {
|
|
8392
|
+
governanceAttachment = "pending";
|
|
8393
|
+
status = "healthy";
|
|
8394
|
+
authorityState = "advisory";
|
|
8395
|
+
} else if (planFetchError) {
|
|
8396
|
+
governanceAttachment = "fetch_failed";
|
|
8397
|
+
status = "degraded";
|
|
8398
|
+
authorityState = "inactive";
|
|
8399
|
+
totalErrors = 1;
|
|
8400
|
+
} else if (approvedRuntimeInitError) {
|
|
8401
|
+
const isArtifactInvalid = approvedRuntimeInitError.message.includes("Approved governance artifact");
|
|
8402
|
+
governanceAttachment = isArtifactInvalid ? "artifact_invalid" : "attachment_failed";
|
|
8403
|
+
status = "degraded";
|
|
8404
|
+
authorityState = "inactive";
|
|
8405
|
+
totalErrors = 1;
|
|
8406
|
+
} else if (!hasApprovedGovernanceArtifact(governancePlan)) {
|
|
8407
|
+
governanceAttachment = "no_plan";
|
|
8408
|
+
status = "healthy";
|
|
8409
|
+
authorityState = "advisory";
|
|
8410
|
+
} else {
|
|
8411
|
+
governanceAttachment = "pending";
|
|
8412
|
+
status = "healthy";
|
|
8413
|
+
authorityState = "advisory";
|
|
8414
|
+
}
|
|
8415
|
+
return {
|
|
8416
|
+
status,
|
|
8417
|
+
authorityState,
|
|
8418
|
+
protectionLevel: observeProtectionLevel,
|
|
8419
|
+
durability: "inactive",
|
|
8420
|
+
tier: "compat",
|
|
8421
|
+
compatEnforcement: "protective",
|
|
8422
|
+
cluster_detected: false,
|
|
8423
|
+
bypass_detected: false,
|
|
8424
|
+
totalSteps: 0,
|
|
8425
|
+
totalBlocks: 0,
|
|
8426
|
+
totalErrors,
|
|
8427
|
+
killed: false,
|
|
8428
|
+
shadowEvaluations: 0,
|
|
8429
|
+
governanceAttachment
|
|
8430
|
+
};
|
|
8431
|
+
},
|
|
8432
|
+
getState: () => approvedRuntimeSession ? approvedRuntimeSession.getState() : EMPTY_STATE_SNAPSHOT,
|
|
8433
|
+
getLastNarrowing: () => approvedRuntimeSession ? approvedRuntimeSession.getLastNarrowing() : null,
|
|
8434
|
+
getLastShadowDelta: () => approvedRuntimeSession ? approvedRuntimeSession.getLastShadowDelta() : null,
|
|
8435
|
+
getLastTrace: () => approvedRuntimeSession ? approvedRuntimeSession.getLastTrace() : null,
|
|
8436
|
+
narrow(...args) {
|
|
8437
|
+
approvedRuntimeSession?.narrow(...args);
|
|
8076
8438
|
},
|
|
8077
8439
|
widen() {
|
|
8440
|
+
approvedRuntimeSession?.widen();
|
|
8078
8441
|
},
|
|
8079
|
-
addLabel() {
|
|
8442
|
+
addLabel(label) {
|
|
8443
|
+
approvedRuntimeSession?.addLabel(label);
|
|
8080
8444
|
},
|
|
8081
|
-
tools
|
|
8082
|
-
getWorkflowState: () => Promise.resolve(null),
|
|
8083
|
-
handoff: () => Promise.resolve(null)
|
|
8445
|
+
tools,
|
|
8446
|
+
getWorkflowState: () => approvedRuntimeSession ? approvedRuntimeSession.getWorkflowState() : Promise.resolve(null),
|
|
8447
|
+
handoff: (offer) => approvedRuntimeSession ? approvedRuntimeSession.handoff(offer) : Promise.resolve(null)
|
|
8084
8448
|
};
|
|
8085
8449
|
}
|
|
8086
8450
|
function toNarrowingSnapshot(result) {
|
|
@@ -8257,6 +8621,9 @@ function determineProtectionLevel(mode, tools, contracts, apiKey) {
|
|
|
8257
8621
|
const allWrapped = stateBearingTools.every((c) => wrappedTools.has(c.tool));
|
|
8258
8622
|
return allWrapped ? "govern" : "protect";
|
|
8259
8623
|
}
|
|
8624
|
+
function determineRuntimeFreeProtectionLevel(mode) {
|
|
8625
|
+
return mode === "enforce" ? "protect" : "monitor";
|
|
8626
|
+
}
|
|
8260
8627
|
function isStateBearing(contract) {
|
|
8261
8628
|
if (contract.commit_requirement != null && contract.commit_requirement !== "none") return true;
|
|
8262
8629
|
if (contract.transitions != null) return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@replayci/replay",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "ReplayCI SDK for deterministic tool-call validation and observation.",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "ReplayCI",
|
|
@@ -45,12 +45,14 @@
|
|
|
45
45
|
],
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
48
|
+
"postbuild": "node scripts/check-dist-parity.mjs",
|
|
48
49
|
"prepublishOnly": "npm run build",
|
|
50
|
+
"check-dist": "node scripts/check-dist-parity.mjs",
|
|
49
51
|
"typecheck": "tsc --noEmit",
|
|
50
52
|
"test": "vitest run"
|
|
51
53
|
},
|
|
52
54
|
"dependencies": {
|
|
53
|
-
"@replayci/contracts-core": "^0.1.
|
|
55
|
+
"@replayci/contracts-core": "^0.1.11",
|
|
54
56
|
"re2": "^1.20.0",
|
|
55
57
|
"yaml": "^2.0.0"
|
|
56
58
|
},
|