tryassay 0.6.0 → 0.11.1
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/api/pricing-enforcer.d.ts +45 -0
- package/dist/api/pricing-enforcer.js +144 -0
- package/dist/api/pricing-enforcer.js.map +1 -0
- package/dist/api/server.d.ts +28 -0
- package/dist/api/server.js +265 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/team-session.d.ts +59 -0
- package/dist/api/team-session.js +240 -0
- package/dist/api/team-session.js.map +1 -0
- package/dist/cli.js +123 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/api.d.ts +4 -0
- package/dist/commands/api.js +50 -0
- package/dist/commands/api.js.map +1 -0
- package/dist/commands/runtime.d.ts +61 -0
- package/dist/commands/runtime.js +554 -0
- package/dist/commands/runtime.js.map +1 -1
- package/dist/runtime/agent-spawner.d.ts +56 -0
- package/dist/runtime/agent-spawner.js +217 -0
- package/dist/runtime/agent-spawner.js.map +1 -0
- package/dist/runtime/agents/coordinator-agent.d.ts +20 -0
- package/dist/runtime/agents/coordinator-agent.js +182 -0
- package/dist/runtime/agents/coordinator-agent.js.map +1 -0
- package/dist/runtime/agents/ops-agent.d.ts +11 -0
- package/dist/runtime/agents/ops-agent.js +113 -0
- package/dist/runtime/agents/ops-agent.js.map +1 -0
- package/dist/runtime/agents/research-agent.d.ts +11 -0
- package/dist/runtime/agents/research-agent.js +114 -0
- package/dist/runtime/agents/research-agent.js.map +1 -0
- package/dist/runtime/agents/test-agent.d.ts +11 -0
- package/dist/runtime/agents/test-agent.js +114 -0
- package/dist/runtime/agents/test-agent.js.map +1 -0
- package/dist/runtime/audit-log.js +2 -2
- package/dist/runtime/audit-log.js.map +1 -1
- package/dist/runtime/capability-registry.d.ts +62 -0
- package/dist/runtime/capability-registry.js +191 -0
- package/dist/runtime/capability-registry.js.map +1 -0
- package/dist/runtime/collusion-detector.d.ts +35 -0
- package/dist/runtime/collusion-detector.js +97 -0
- package/dist/runtime/collusion-detector.js.map +1 -0
- package/dist/runtime/control-server.js +8 -4
- package/dist/runtime/control-server.js.map +1 -1
- package/dist/runtime/domain-coverage-analyzer.d.ts +24 -0
- package/dist/runtime/domain-coverage-analyzer.js +178 -0
- package/dist/runtime/domain-coverage-analyzer.js.map +1 -0
- package/dist/runtime/executor.js +27 -12
- package/dist/runtime/executor.js.map +1 -1
- package/dist/runtime/human-escalation.d.ts +41 -0
- package/dist/runtime/human-escalation.js +122 -0
- package/dist/runtime/human-escalation.js.map +1 -0
- package/dist/runtime/kill-switch.d.ts +51 -0
- package/dist/runtime/kill-switch.js +185 -0
- package/dist/runtime/kill-switch.js.map +1 -0
- package/dist/runtime/layer2-guardian.d.ts +81 -0
- package/dist/runtime/layer2-guardian.js +263 -0
- package/dist/runtime/layer2-guardian.js.map +1 -0
- package/dist/runtime/multi-agent-loop.d.ts +37 -0
- package/dist/runtime/multi-agent-loop.js +411 -0
- package/dist/runtime/multi-agent-loop.js.map +1 -0
- package/dist/runtime/prompt-safety-analyzer.d.ts +17 -0
- package/dist/runtime/prompt-safety-analyzer.js +230 -0
- package/dist/runtime/prompt-safety-analyzer.js.map +1 -0
- package/dist/runtime/rollback-manager.d.ts +50 -0
- package/dist/runtime/rollback-manager.js +157 -0
- package/dist/runtime/rollback-manager.js.map +1 -0
- package/dist/runtime/rule-canary-deployer.d.ts +69 -0
- package/dist/runtime/rule-canary-deployer.js +289 -0
- package/dist/runtime/rule-canary-deployer.js.map +1 -0
- package/dist/runtime/rule-conflict-detector.d.ts +48 -0
- package/dist/runtime/rule-conflict-detector.js +214 -0
- package/dist/runtime/rule-conflict-detector.js.map +1 -0
- package/dist/runtime/rule-meta-verifier.d.ts +18 -0
- package/dist/runtime/rule-meta-verifier.js +275 -0
- package/dist/runtime/rule-meta-verifier.js.map +1 -0
- package/dist/runtime/rule-proposal-manager.d.ts +95 -0
- package/dist/runtime/rule-proposal-manager.js +190 -0
- package/dist/runtime/rule-proposal-manager.js.map +1 -0
- package/dist/runtime/safety-enforcer.d.ts +35 -0
- package/dist/runtime/safety-enforcer.js +165 -0
- package/dist/runtime/safety-enforcer.js.map +1 -0
- package/dist/runtime/safety-status.d.ts +48 -0
- package/dist/runtime/safety-status.js +119 -0
- package/dist/runtime/safety-status.js.map +1 -0
- package/dist/runtime/shared-memory.d.ts +47 -0
- package/dist/runtime/shared-memory.js +151 -0
- package/dist/runtime/shared-memory.js.map +1 -0
- package/dist/runtime/specialized-agent.d.ts +5 -0
- package/dist/runtime/specialized-agent.js +37 -0
- package/dist/runtime/specialized-agent.js.map +1 -1
- package/dist/runtime/stall-detector.d.ts +13 -0
- package/dist/runtime/stall-detector.js +121 -0
- package/dist/runtime/stall-detector.js.map +1 -0
- package/dist/runtime/tool-approval.d.ts +51 -0
- package/dist/runtime/tool-approval.js +148 -0
- package/dist/runtime/tool-approval.js.map +1 -0
- package/dist/runtime/tool-sandbox.d.ts +43 -0
- package/dist/runtime/tool-sandbox.js +394 -0
- package/dist/runtime/tool-sandbox.js.map +1 -0
- package/dist/runtime/tool-verifier.d.ts +18 -0
- package/dist/runtime/tool-verifier.js +323 -0
- package/dist/runtime/tool-verifier.js.map +1 -0
- package/dist/runtime/trust-manager.d.ts +33 -3
- package/dist/runtime/trust-manager.js +128 -26
- package/dist/runtime/trust-manager.js.map +1 -1
- package/dist/runtime/types.d.ts +652 -0
- package/dist/runtime/verification-intensity.d.ts +34 -0
- package/dist/runtime/verification-intensity.js +104 -0
- package/dist/runtime/verification-intensity.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Assay Verified Agent Runtime — Stall Detector
|
|
3
|
+
// Monitors task graph for timeouts, reject loops,
|
|
4
|
+
// dependency deadlocks, and resource contention.
|
|
5
|
+
// ============================================================
|
|
6
|
+
// ── Stall Detector ─────────────────────────────────────────
|
|
7
|
+
export class StallDetector {
|
|
8
|
+
/**
|
|
9
|
+
* Detect stalls in a task graph.
|
|
10
|
+
* Returns stall reports for any problematic tasks.
|
|
11
|
+
*/
|
|
12
|
+
detectStalls(graph, thresholdMs) {
|
|
13
|
+
const reports = [];
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
for (const task of graph.tasks) {
|
|
16
|
+
// Skip completed or failed tasks
|
|
17
|
+
if (task.status === 'completed' || task.status === 'failed')
|
|
18
|
+
continue;
|
|
19
|
+
// Check for timeout: task in progress for too long
|
|
20
|
+
if (task.status === 'in_progress' || task.status === 'assigned') {
|
|
21
|
+
const taskStart = new Date(task.createdAt).getTime();
|
|
22
|
+
const elapsed = now - taskStart;
|
|
23
|
+
if (elapsed > thresholdMs) {
|
|
24
|
+
reports.push({
|
|
25
|
+
taskId: task.id,
|
|
26
|
+
type: 'timeout',
|
|
27
|
+
duration: elapsed,
|
|
28
|
+
attempts: task.attempts,
|
|
29
|
+
suggestedAction: task.attempts >= task.maxAttempts ? 'escalate' : 'reassign',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Check for reject loop: task rejected too many times
|
|
34
|
+
if (task.status === 'rejected' && task.attempts >= task.maxAttempts) {
|
|
35
|
+
reports.push({
|
|
36
|
+
taskId: task.id,
|
|
37
|
+
type: 'reject_loop',
|
|
38
|
+
duration: now - new Date(task.createdAt).getTime(),
|
|
39
|
+
attempts: task.attempts,
|
|
40
|
+
suggestedAction: task.attempts >= task.maxAttempts ? 'escalate' : 'simplify',
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
// Check for resource contention: multiple tasks waiting for the same specialization
|
|
44
|
+
if (task.status === 'ready' || task.status === 'pending') {
|
|
45
|
+
const waitingForSameSpec = graph.tasks.filter(t => t.id !== task.id &&
|
|
46
|
+
t.specialization === task.specialization &&
|
|
47
|
+
(t.status === 'in_progress' || t.status === 'assigned'));
|
|
48
|
+
if (waitingForSameSpec.length >= 2) {
|
|
49
|
+
reports.push({
|
|
50
|
+
taskId: task.id,
|
|
51
|
+
type: 'resource_contention',
|
|
52
|
+
duration: now - new Date(task.createdAt).getTime(),
|
|
53
|
+
attempts: task.attempts,
|
|
54
|
+
suggestedAction: 'reassign',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Check for dependency deadlocks: circular dependencies
|
|
60
|
+
const deadlockTasks = this.detectDeadlocks(graph);
|
|
61
|
+
for (const taskId of deadlockTasks) {
|
|
62
|
+
const task = graph.tasks.find(t => t.id === taskId);
|
|
63
|
+
if (task) {
|
|
64
|
+
reports.push({
|
|
65
|
+
taskId: task.id,
|
|
66
|
+
type: 'dependency_deadlock',
|
|
67
|
+
duration: now - new Date(task.createdAt).getTime(),
|
|
68
|
+
attempts: task.attempts,
|
|
69
|
+
suggestedAction: 'abort',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return reports;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Detect circular dependencies in the task graph.
|
|
77
|
+
* Returns task IDs involved in deadlock cycles.
|
|
78
|
+
*/
|
|
79
|
+
detectDeadlocks(graph) {
|
|
80
|
+
const deadlocked = new Set();
|
|
81
|
+
// Build adjacency list from blocking edges
|
|
82
|
+
const blockingEdges = graph.edges.filter(e => e.type === 'blocks');
|
|
83
|
+
const adjacency = new Map();
|
|
84
|
+
for (const edge of blockingEdges) {
|
|
85
|
+
const existing = adjacency.get(edge.from) ?? [];
|
|
86
|
+
existing.push(edge.to);
|
|
87
|
+
adjacency.set(edge.from, existing);
|
|
88
|
+
}
|
|
89
|
+
// DFS-based cycle detection
|
|
90
|
+
const visited = new Set();
|
|
91
|
+
const inStack = new Set();
|
|
92
|
+
const dfs = (taskId) => {
|
|
93
|
+
if (inStack.has(taskId)) {
|
|
94
|
+
// Found a cycle — collect all tasks in the cycle
|
|
95
|
+
deadlocked.add(taskId);
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
if (visited.has(taskId))
|
|
99
|
+
return false;
|
|
100
|
+
visited.add(taskId);
|
|
101
|
+
inStack.add(taskId);
|
|
102
|
+
const neighbors = adjacency.get(taskId) ?? [];
|
|
103
|
+
for (const neighbor of neighbors) {
|
|
104
|
+
if (dfs(neighbor)) {
|
|
105
|
+
deadlocked.add(taskId);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
inStack.delete(taskId);
|
|
109
|
+
return false;
|
|
110
|
+
};
|
|
111
|
+
// Only check tasks that are not yet completed
|
|
112
|
+
const activeTasks = graph.tasks
|
|
113
|
+
.filter(t => t.status !== 'completed' && t.status !== 'failed')
|
|
114
|
+
.map(t => t.id);
|
|
115
|
+
for (const taskId of activeTasks) {
|
|
116
|
+
dfs(taskId);
|
|
117
|
+
}
|
|
118
|
+
return Array.from(deadlocked);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=stall-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stall-detector.js","sourceRoot":"","sources":["../../src/runtime/stall-detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ToolDefinition, ToolVerification, ModificationProposal, ModificationApproval, ProposalStatus } from './types.js';
|
|
2
|
+
import { ToolVerifier } from './tool-verifier.js';
|
|
3
|
+
import { CapabilityRegistryManager } from './capability-registry.js';
|
|
4
|
+
export interface PendingApproval {
|
|
5
|
+
readonly proposal: ModificationProposal;
|
|
6
|
+
readonly verification: ToolVerification;
|
|
7
|
+
readonly toolDefinition: ToolDefinition;
|
|
8
|
+
readonly toolSourceDir: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class ToolApprovalManager {
|
|
11
|
+
private verifier;
|
|
12
|
+
private registry;
|
|
13
|
+
private pendingApprovals;
|
|
14
|
+
private approvalHistoryPath;
|
|
15
|
+
constructor(registry: CapabilityRegistryManager, verifier?: ToolVerifier, approvalHistoryPath?: string);
|
|
16
|
+
/**
|
|
17
|
+
* Propose a new tool. Runs verification and queues for human approval.
|
|
18
|
+
* Returns the proposal ID and verification result.
|
|
19
|
+
*/
|
|
20
|
+
propose(tool: ToolDefinition, toolSourceDir: string, justification: {
|
|
21
|
+
capability_gap: string;
|
|
22
|
+
evidence: string[];
|
|
23
|
+
expected_impact: string;
|
|
24
|
+
risk_assessment: string;
|
|
25
|
+
}): Promise<{
|
|
26
|
+
proposalId: string;
|
|
27
|
+
verification: ToolVerification;
|
|
28
|
+
status: ProposalStatus;
|
|
29
|
+
}>;
|
|
30
|
+
/**
|
|
31
|
+
* List all pending approvals.
|
|
32
|
+
*/
|
|
33
|
+
listPending(): PendingApproval[];
|
|
34
|
+
/**
|
|
35
|
+
* Get a specific pending approval.
|
|
36
|
+
*/
|
|
37
|
+
getPending(proposalId: string): PendingApproval | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Approve a pending tool proposal. Activates the tool in the registry.
|
|
40
|
+
*/
|
|
41
|
+
approve(proposalId: string, approvedBy: string, reasoning: string, conditions?: string[]): Promise<ModificationApproval>;
|
|
42
|
+
/**
|
|
43
|
+
* Reject a pending tool proposal.
|
|
44
|
+
*/
|
|
45
|
+
reject(proposalId: string, rejectedBy: string, reasoning: string): Promise<ModificationApproval>;
|
|
46
|
+
/**
|
|
47
|
+
* Rollback the last registry change.
|
|
48
|
+
*/
|
|
49
|
+
rollback(rolledBackBy: string): Promise<boolean>;
|
|
50
|
+
private logApproval;
|
|
51
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// Assay Verified Agent Runtime — Tool Approval Flow
|
|
3
|
+
// Orchestrates: propose → verify → approve → activate
|
|
4
|
+
// Human approval is required before any tool goes active.
|
|
5
|
+
// ============================================================
|
|
6
|
+
import { randomUUID } from 'node:crypto';
|
|
7
|
+
import { mkdir, appendFile } from 'node:fs/promises';
|
|
8
|
+
import { dirname } from 'node:path';
|
|
9
|
+
import { ToolVerifier } from './tool-verifier.js';
|
|
10
|
+
// ── Tool Approval Manager ──────────────────────────────────
|
|
11
|
+
export class ToolApprovalManager {
|
|
12
|
+
verifier;
|
|
13
|
+
registry;
|
|
14
|
+
pendingApprovals = new Map();
|
|
15
|
+
approvalHistoryPath;
|
|
16
|
+
constructor(registry, verifier, approvalHistoryPath) {
|
|
17
|
+
this.registry = registry;
|
|
18
|
+
this.verifier = verifier ?? new ToolVerifier();
|
|
19
|
+
this.approvalHistoryPath = approvalHistoryPath ?? '.assay/tool-approvals.ndjson';
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Propose a new tool. Runs verification and queues for human approval.
|
|
23
|
+
* Returns the proposal ID and verification result.
|
|
24
|
+
*/
|
|
25
|
+
async propose(tool, toolSourceDir, justification) {
|
|
26
|
+
const proposalId = `mod_${Date.now()}_${randomUUID().slice(0, 8)}`;
|
|
27
|
+
// Create the proposal
|
|
28
|
+
const proposal = {
|
|
29
|
+
id: proposalId,
|
|
30
|
+
type: 'tool',
|
|
31
|
+
timestamp: new Date().toISOString(),
|
|
32
|
+
title: `New tool: ${tool.name}`,
|
|
33
|
+
description: tool.description,
|
|
34
|
+
payload: tool,
|
|
35
|
+
justification,
|
|
36
|
+
safety: {
|
|
37
|
+
modifies_layer2: false,
|
|
38
|
+
modifies_approval_framework: false,
|
|
39
|
+
trust_level_required: 'provisional',
|
|
40
|
+
rollback_plan: `Deprecate tool ${tool.id} and rollback registry`,
|
|
41
|
+
},
|
|
42
|
+
proposed_by: tool.created_by,
|
|
43
|
+
status: 'verifying',
|
|
44
|
+
};
|
|
45
|
+
// Run verification
|
|
46
|
+
const verification = await this.verifier.verify(tool, toolSourceDir);
|
|
47
|
+
// Update proposal status based on verification
|
|
48
|
+
let status;
|
|
49
|
+
if (verification.verdict === 'reject') {
|
|
50
|
+
status = 'rejected';
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
status = 'pending_approval';
|
|
54
|
+
// Queue for human approval
|
|
55
|
+
this.pendingApprovals.set(proposalId, {
|
|
56
|
+
proposal: { ...proposal, status, verification_id: verification.verification_id },
|
|
57
|
+
verification,
|
|
58
|
+
toolDefinition: tool,
|
|
59
|
+
toolSourceDir,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return { proposalId, verification, status };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* List all pending approvals.
|
|
66
|
+
*/
|
|
67
|
+
listPending() {
|
|
68
|
+
return Array.from(this.pendingApprovals.values());
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get a specific pending approval.
|
|
72
|
+
*/
|
|
73
|
+
getPending(proposalId) {
|
|
74
|
+
return this.pendingApprovals.get(proposalId);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Approve a pending tool proposal. Activates the tool in the registry.
|
|
78
|
+
*/
|
|
79
|
+
async approve(proposalId, approvedBy, reasoning, conditions) {
|
|
80
|
+
const pending = this.pendingApprovals.get(proposalId);
|
|
81
|
+
if (!pending) {
|
|
82
|
+
throw new Error(`No pending approval found for proposal "${proposalId}"`);
|
|
83
|
+
}
|
|
84
|
+
const approval = {
|
|
85
|
+
proposal_id: proposalId,
|
|
86
|
+
decision: 'approved',
|
|
87
|
+
decided_by: approvedBy,
|
|
88
|
+
decided_at: new Date().toISOString(),
|
|
89
|
+
reasoning,
|
|
90
|
+
conditions,
|
|
91
|
+
};
|
|
92
|
+
// Activate the tool in the registry
|
|
93
|
+
const approvedTool = {
|
|
94
|
+
...pending.toolDefinition,
|
|
95
|
+
status: 'approved',
|
|
96
|
+
};
|
|
97
|
+
this.registry.addTool(approvedTool, approvedBy, proposalId);
|
|
98
|
+
await this.registry.save();
|
|
99
|
+
// Remove from pending
|
|
100
|
+
this.pendingApprovals.delete(proposalId);
|
|
101
|
+
// Log the approval
|
|
102
|
+
await this.logApproval(approval);
|
|
103
|
+
return approval;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Reject a pending tool proposal.
|
|
107
|
+
*/
|
|
108
|
+
async reject(proposalId, rejectedBy, reasoning) {
|
|
109
|
+
const pending = this.pendingApprovals.get(proposalId);
|
|
110
|
+
if (!pending) {
|
|
111
|
+
throw new Error(`No pending approval found for proposal "${proposalId}"`);
|
|
112
|
+
}
|
|
113
|
+
const approval = {
|
|
114
|
+
proposal_id: proposalId,
|
|
115
|
+
decision: 'rejected',
|
|
116
|
+
decided_by: rejectedBy,
|
|
117
|
+
decided_at: new Date().toISOString(),
|
|
118
|
+
reasoning,
|
|
119
|
+
};
|
|
120
|
+
// Remove from pending
|
|
121
|
+
this.pendingApprovals.delete(proposalId);
|
|
122
|
+
// Log the rejection
|
|
123
|
+
await this.logApproval(approval);
|
|
124
|
+
return approval;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Rollback the last registry change.
|
|
128
|
+
*/
|
|
129
|
+
async rollback(rolledBackBy) {
|
|
130
|
+
const success = this.registry.rollback(rolledBackBy);
|
|
131
|
+
if (success) {
|
|
132
|
+
await this.registry.save();
|
|
133
|
+
}
|
|
134
|
+
return success;
|
|
135
|
+
}
|
|
136
|
+
// ── Private ──────────────────────────────────────────────
|
|
137
|
+
async logApproval(approval) {
|
|
138
|
+
try {
|
|
139
|
+
await mkdir(dirname(this.approvalHistoryPath), { recursive: true });
|
|
140
|
+
const line = JSON.stringify(approval) + '\n';
|
|
141
|
+
await appendFile(this.approvalHistoryPath, line, 'utf-8');
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
// Non-critical: approval history logging failure doesn't block the flow
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=tool-approval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-approval.js","sourceRoot":"","sources":["../../src/runtime/tool-approval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ToolDefinition, ToolConstraints, ToolTestResult } from './types.js';
|
|
2
|
+
export interface SandboxRequest {
|
|
3
|
+
readonly toolId: string;
|
|
4
|
+
readonly entryPoint: string;
|
|
5
|
+
readonly functionName: string;
|
|
6
|
+
readonly input: unknown;
|
|
7
|
+
readonly constraints: ToolConstraints;
|
|
8
|
+
}
|
|
9
|
+
export interface SandboxResponse {
|
|
10
|
+
readonly status: 'success' | 'error' | 'timeout' | 'constraint_violation';
|
|
11
|
+
readonly output?: unknown;
|
|
12
|
+
readonly error?: string;
|
|
13
|
+
readonly durationMs: number;
|
|
14
|
+
readonly memoryUsageMb?: number;
|
|
15
|
+
readonly networkAttempts?: readonly string[];
|
|
16
|
+
readonly filesystemWrites?: readonly string[];
|
|
17
|
+
}
|
|
18
|
+
export declare class ToolSandbox {
|
|
19
|
+
private sandboxDir;
|
|
20
|
+
constructor(sandboxBaseDir?: string);
|
|
21
|
+
/**
|
|
22
|
+
* Execute a tool in a sandboxed child process.
|
|
23
|
+
* Enforces all constraints from the ToolDefinition.
|
|
24
|
+
*/
|
|
25
|
+
execute(request: SandboxRequest): Promise<SandboxResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Run a full test suite against a tool: happy path, malformed input,
|
|
28
|
+
* timeout behavior, and constraint compliance.
|
|
29
|
+
*/
|
|
30
|
+
runTestSuite(tool: ToolDefinition, toolSourceDir: string): Promise<{
|
|
31
|
+
happy_path: ToolTestResult;
|
|
32
|
+
malformed_input: ToolTestResult;
|
|
33
|
+
timeout_behavior: ToolTestResult;
|
|
34
|
+
constraint_compliance: ToolTestResult;
|
|
35
|
+
}>;
|
|
36
|
+
private forkAndRun;
|
|
37
|
+
private generateRunnerScript;
|
|
38
|
+
private runSingleTest;
|
|
39
|
+
private runTimeoutTest;
|
|
40
|
+
private runConstraintComplianceTest;
|
|
41
|
+
private generateHappyPathInput;
|
|
42
|
+
private generateMalformedInput;
|
|
43
|
+
}
|