@mondaydotcomorg/atp-server 0.17.14
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/README.md +489 -0
- package/dist/aggregator/index.d.ts +59 -0
- package/dist/aggregator/index.d.ts.map +1 -0
- package/dist/aggregator/index.js +171 -0
- package/dist/aggregator/index.js.map +1 -0
- package/dist/callback/index.d.ts +98 -0
- package/dist/callback/index.d.ts.map +1 -0
- package/dist/callback/index.js +136 -0
- package/dist/callback/index.js.map +1 -0
- package/dist/client-sessions.d.ts +82 -0
- package/dist/client-sessions.d.ts.map +1 -0
- package/dist/client-sessions.js +174 -0
- package/dist/client-sessions.js.map +1 -0
- package/dist/controllers/definitions.controller.d.ts +4 -0
- package/dist/controllers/definitions.controller.d.ts.map +1 -0
- package/dist/controllers/definitions.controller.js +11 -0
- package/dist/controllers/definitions.controller.js.map +1 -0
- package/dist/controllers/execute.controller.d.ts +18 -0
- package/dist/controllers/execute.controller.d.ts.map +1 -0
- package/dist/controllers/execute.controller.js +122 -0
- package/dist/controllers/execute.controller.js.map +1 -0
- package/dist/controllers/info.controller.d.ts +3 -0
- package/dist/controllers/info.controller.d.ts.map +1 -0
- package/dist/controllers/info.controller.js +13 -0
- package/dist/controllers/info.controller.js.map +1 -0
- package/dist/controllers/resume.controller.d.ts +11 -0
- package/dist/controllers/resume.controller.d.ts.map +1 -0
- package/dist/controllers/resume.controller.js +61 -0
- package/dist/controllers/resume.controller.js.map +1 -0
- package/dist/controllers/search.controller.d.ts +4 -0
- package/dist/controllers/search.controller.d.ts.map +1 -0
- package/dist/controllers/search.controller.js +7 -0
- package/dist/controllers/search.controller.js.map +1 -0
- package/dist/controllers/stream.controller.d.ts +19 -0
- package/dist/controllers/stream.controller.d.ts.map +1 -0
- package/dist/controllers/stream.controller.js +141 -0
- package/dist/controllers/stream.controller.js.map +1 -0
- package/dist/core/config.d.ts +161 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +7 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/http.d.ts +4 -0
- package/dist/core/http.d.ts.map +1 -0
- package/dist/core/http.js +17 -0
- package/dist/core/http.js.map +1 -0
- package/dist/create-server.d.ts +120 -0
- package/dist/create-server.d.ts.map +1 -0
- package/dist/create-server.js +423 -0
- package/dist/create-server.js.map +1 -0
- package/dist/execution-state/index.d.ts +95 -0
- package/dist/execution-state/index.d.ts.map +1 -0
- package/dist/execution-state/index.js +128 -0
- package/dist/execution-state/index.js.map +1 -0
- package/dist/executor/ast-provenance-bridge.d.ts +12 -0
- package/dist/executor/ast-provenance-bridge.d.ts.map +1 -0
- package/dist/executor/ast-provenance-bridge.js +66 -0
- package/dist/executor/ast-provenance-bridge.js.map +1 -0
- package/dist/executor/ast-tracking-runtime.d.ts +7 -0
- package/dist/executor/ast-tracking-runtime.d.ts.map +1 -0
- package/dist/executor/ast-tracking-runtime.js +559 -0
- package/dist/executor/ast-tracking-runtime.js.map +1 -0
- package/dist/executor/bootstrap-generated.d.ts +32 -0
- package/dist/executor/bootstrap-generated.d.ts.map +1 -0
- package/dist/executor/bootstrap-generated.js +90 -0
- package/dist/executor/bootstrap-generated.js.map +1 -0
- package/dist/executor/compiler-config.d.ts +32 -0
- package/dist/executor/compiler-config.d.ts.map +1 -0
- package/dist/executor/compiler-config.js +99 -0
- package/dist/executor/compiler-config.js.map +1 -0
- package/dist/executor/constants.d.ts +4 -0
- package/dist/executor/constants.d.ts.map +1 -0
- package/dist/executor/constants.js +4 -0
- package/dist/executor/constants.js.map +1 -0
- package/dist/executor/error-handler.d.ts +9 -0
- package/dist/executor/error-handler.d.ts.map +1 -0
- package/dist/executor/error-handler.js +95 -0
- package/dist/executor/error-handler.js.map +1 -0
- package/dist/executor/execution-error-handler.d.ts +7 -0
- package/dist/executor/execution-error-handler.d.ts.map +1 -0
- package/dist/executor/execution-error-handler.js +136 -0
- package/dist/executor/execution-error-handler.js.map +1 -0
- package/dist/executor/executor.d.ts +20 -0
- package/dist/executor/executor.d.ts.map +1 -0
- package/dist/executor/executor.js +452 -0
- package/dist/executor/executor.js.map +1 -0
- package/dist/executor/index.d.ts +4 -0
- package/dist/executor/index.d.ts.map +1 -0
- package/dist/executor/index.js +3 -0
- package/dist/executor/index.js.map +1 -0
- package/dist/executor/resume-handler.d.ts +9 -0
- package/dist/executor/resume-handler.d.ts.map +1 -0
- package/dist/executor/resume-handler.js +22 -0
- package/dist/executor/resume-handler.js.map +1 -0
- package/dist/executor/sandbox-builder.d.ts +29 -0
- package/dist/executor/sandbox-builder.d.ts.map +1 -0
- package/dist/executor/sandbox-builder.js +538 -0
- package/dist/executor/sandbox-builder.js.map +1 -0
- package/dist/executor/sandbox-injector.d.ts +7 -0
- package/dist/executor/sandbox-injector.d.ts.map +1 -0
- package/dist/executor/sandbox-injector.js +293 -0
- package/dist/executor/sandbox-injector.js.map +1 -0
- package/dist/executor/types.d.ts +21 -0
- package/dist/executor/types.d.ts.map +1 -0
- package/dist/executor/types.js +2 -0
- package/dist/executor/types.js.map +1 -0
- package/dist/explorer/index.d.ts +69 -0
- package/dist/explorer/index.d.ts.map +1 -0
- package/dist/explorer/index.js +228 -0
- package/dist/explorer/index.js.map +1 -0
- package/dist/handlers/definitions.handler.d.ts +3 -0
- package/dist/handlers/definitions.handler.d.ts.map +1 -0
- package/dist/handlers/definitions.handler.js +11 -0
- package/dist/handlers/definitions.handler.js.map +1 -0
- package/dist/handlers/execute.handler.d.ts +7 -0
- package/dist/handlers/execute.handler.d.ts.map +1 -0
- package/dist/handlers/execute.handler.js +225 -0
- package/dist/handlers/execute.handler.js.map +1 -0
- package/dist/handlers/explorer.handler.d.ts +4 -0
- package/dist/handlers/explorer.handler.d.ts.map +1 -0
- package/dist/handlers/explorer.handler.js +10 -0
- package/dist/handlers/explorer.handler.js.map +1 -0
- package/dist/handlers/init.handler.d.ts +5 -0
- package/dist/handlers/init.handler.d.ts.map +1 -0
- package/dist/handlers/init.handler.js +41 -0
- package/dist/handlers/init.handler.js.map +1 -0
- package/dist/handlers/resume.handler.d.ts +6 -0
- package/dist/handlers/resume.handler.d.ts.map +1 -0
- package/dist/handlers/resume.handler.js +256 -0
- package/dist/handlers/resume.handler.js.map +1 -0
- package/dist/handlers/search.handler.d.ts +5 -0
- package/dist/handlers/search.handler.d.ts.map +1 -0
- package/dist/handlers/search.handler.js +11 -0
- package/dist/handlers/search.handler.js.map +1 -0
- package/dist/http/request-handler.d.ts +15 -0
- package/dist/http/request-handler.d.ts.map +1 -0
- package/dist/http/request-handler.js +94 -0
- package/dist/http/request-handler.js.map +1 -0
- package/dist/http/router.d.ts +4 -0
- package/dist/http/router.d.ts.map +1 -0
- package/dist/http/router.js +32 -0
- package/dist/http/router.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/instrumentation/index.d.ts +5 -0
- package/dist/instrumentation/index.d.ts.map +1 -0
- package/dist/instrumentation/index.js +5 -0
- package/dist/instrumentation/index.js.map +1 -0
- package/dist/instrumentation/serializer.d.ts +61 -0
- package/dist/instrumentation/serializer.d.ts.map +1 -0
- package/dist/instrumentation/serializer.js +334 -0
- package/dist/instrumentation/serializer.js.map +1 -0
- package/dist/instrumentation/state-manager.d.ts +61 -0
- package/dist/instrumentation/state-manager.d.ts.map +1 -0
- package/dist/instrumentation/state-manager.js +205 -0
- package/dist/instrumentation/state-manager.js.map +1 -0
- package/dist/instrumentation/transformer.d.ts +9 -0
- package/dist/instrumentation/transformer.d.ts.map +1 -0
- package/dist/instrumentation/transformer.js +70 -0
- package/dist/instrumentation/transformer.js.map +1 -0
- package/dist/instrumentation/types.d.ts +59 -0
- package/dist/instrumentation/types.d.ts.map +1 -0
- package/dist/instrumentation/types.js +5 -0
- package/dist/instrumentation/types.js.map +1 -0
- package/dist/middleware/audit.d.ts +18 -0
- package/dist/middleware/audit.d.ts.map +1 -0
- package/dist/middleware/audit.js +76 -0
- package/dist/middleware/audit.js.map +1 -0
- package/dist/openapi/index.d.ts +133 -0
- package/dist/openapi/index.d.ts.map +1 -0
- package/dist/openapi/index.js +235 -0
- package/dist/openapi/index.js.map +1 -0
- package/dist/openapi-loader.d.ts +87 -0
- package/dist/openapi-loader.d.ts.map +1 -0
- package/dist/openapi-loader.js +491 -0
- package/dist/openapi-loader.js.map +1 -0
- package/dist/routes/index.d.ts +21 -0
- package/dist/routes/index.d.ts.map +1 -0
- package/dist/routes/index.js +47 -0
- package/dist/routes/index.js.map +1 -0
- package/dist/search/index.d.ts +48 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +156 -0
- package/dist/search/index.js.map +1 -0
- package/dist/security/index.d.ts +2 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +2 -0
- package/dist/security/index.js.map +1 -0
- package/dist/shutdown.d.ts +19 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +87 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/utils/banner.d.ts +12 -0
- package/dist/utils/banner.d.ts.map +1 -0
- package/dist/utils/banner.js +18 -0
- package/dist/utils/banner.js.map +1 -0
- package/dist/utils/context.d.ts +16 -0
- package/dist/utils/context.d.ts.map +1 -0
- package/dist/utils/context.js +44 -0
- package/dist/utils/context.js.map +1 -0
- package/dist/utils/error.d.ts +8 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +17 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/hint-based-instrumentation.d.ts +14 -0
- package/dist/utils/hint-based-instrumentation.d.ts.map +1 -0
- package/dist/utils/hint-based-instrumentation.js +84 -0
- package/dist/utils/hint-based-instrumentation.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/info.d.ts +20 -0
- package/dist/utils/info.d.ts.map +1 -0
- package/dist/utils/info.js +15 -0
- package/dist/utils/info.js.map +1 -0
- package/dist/utils/provenance-reattachment.d.ts +32 -0
- package/dist/utils/provenance-reattachment.d.ts.map +1 -0
- package/dist/utils/provenance-reattachment.js +115 -0
- package/dist/utils/provenance-reattachment.js.map +1 -0
- package/dist/utils/request.d.ts +21 -0
- package/dist/utils/request.d.ts.map +1 -0
- package/dist/utils/request.js +44 -0
- package/dist/utils/request.js.map +1 -0
- package/dist/utils/response.d.ts +30 -0
- package/dist/utils/response.d.ts.map +1 -0
- package/dist/utils/response.js +53 -0
- package/dist/utils/response.js.map +1 -0
- package/dist/utils/runtime-types.d.ts +6 -0
- package/dist/utils/runtime-types.d.ts.map +1 -0
- package/dist/utils/runtime-types.js +14 -0
- package/dist/utils/runtime-types.js.map +1 -0
- package/dist/utils/schema.d.ts +9 -0
- package/dist/utils/schema.d.ts.map +1 -0
- package/dist/utils/schema.js +13 -0
- package/dist/utils/schema.js.map +1 -0
- package/dist/utils/token-emitter.d.ts +21 -0
- package/dist/utils/token-emitter.d.ts.map +1 -0
- package/dist/utils/token-emitter.js +129 -0
- package/dist/utils/token-emitter.js.map +1 -0
- package/dist/validator/index.d.ts +36 -0
- package/dist/validator/index.d.ts.map +1 -0
- package/dist/validator/index.js +224 -0
- package/dist/validator/index.js.map +1 -0
- package/package.json +68 -0
- package/src/aggregator/index.ts +207 -0
- package/src/callback/index.ts +191 -0
- package/src/client-sessions.ts +234 -0
- package/src/controllers/definitions.controller.ts +19 -0
- package/src/controllers/execute.controller.ts +166 -0
- package/src/controllers/info.controller.ts +14 -0
- package/src/controllers/resume.controller.ts +92 -0
- package/src/controllers/search.controller.ts +16 -0
- package/src/controllers/stream.controller.ts +190 -0
- package/src/core/config.ts +180 -0
- package/src/core/http.ts +21 -0
- package/src/create-server.ts +536 -0
- package/src/execution-state/index.ts +204 -0
- package/src/executor/ast-provenance-bridge.ts +80 -0
- package/src/executor/ast-tracking-runtime.ts +558 -0
- package/src/executor/bootstrap-generated.ts +90 -0
- package/src/executor/compiler-config.ts +146 -0
- package/src/executor/constants.ts +5 -0
- package/src/executor/error-handler.ts +118 -0
- package/src/executor/execution-error-handler.ts +178 -0
- package/src/executor/executor.ts +631 -0
- package/src/executor/index.ts +3 -0
- package/src/executor/resume-handler.ts +39 -0
- package/src/executor/sandbox-builder.ts +684 -0
- package/src/executor/sandbox-injector.ts +345 -0
- package/src/executor/types.ts +22 -0
- package/src/explorer/index.ts +297 -0
- package/src/handlers/definitions.handler.ts +13 -0
- package/src/handlers/execute.handler.ts +286 -0
- package/src/handlers/explorer.handler.ts +18 -0
- package/src/handlers/init.handler.ts +53 -0
- package/src/handlers/resume.handler.ts +316 -0
- package/src/handlers/search.handler.ts +32 -0
- package/src/http/request-handler.ts +117 -0
- package/src/http/router.ts +29 -0
- package/src/index.ts +60 -0
- package/src/instrumentation/index.ts +4 -0
- package/src/instrumentation/serializer.ts +421 -0
- package/src/instrumentation/state-manager.ts +237 -0
- package/src/instrumentation/transformer.ts +84 -0
- package/src/instrumentation/types.ts +76 -0
- package/src/middleware/audit.ts +101 -0
- package/src/openapi/index.ts +378 -0
- package/src/openapi-loader.ts +744 -0
- package/src/routes/index.ts +93 -0
- package/src/search/index.ts +216 -0
- package/src/security/index.ts +1 -0
- package/src/shutdown.ts +108 -0
- package/src/utils/banner.ts +25 -0
- package/src/utils/context.ts +58 -0
- package/src/utils/error.ts +25 -0
- package/src/utils/hint-based-instrumentation.ts +99 -0
- package/src/utils/index.ts +15 -0
- package/src/utils/info.ts +31 -0
- package/src/utils/provenance-reattachment.ts +144 -0
- package/src/utils/request.ts +53 -0
- package/src/utils/response.ts +69 -0
- package/src/utils/runtime-types.ts +14 -0
- package/src/utils/schema.ts +18 -0
- package/src/utils/token-emitter.ts +182 -0
- package/src/validator/index.ts +253 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ExecutionConfig,
|
|
3
|
+
APIGroupConfig,
|
|
4
|
+
ClientToolDefinition,
|
|
5
|
+
ToolMetadata,
|
|
6
|
+
} from '@mondaydotcomorg/atp-protocol';
|
|
7
|
+
import {
|
|
8
|
+
ToolOperationType,
|
|
9
|
+
ToolSensitivityLevel,
|
|
10
|
+
ProvenanceMode,
|
|
11
|
+
CallbackType,
|
|
12
|
+
ToolOperation,
|
|
13
|
+
} from '@mondaydotcomorg/atp-protocol';
|
|
14
|
+
import {
|
|
15
|
+
llm,
|
|
16
|
+
cache,
|
|
17
|
+
log,
|
|
18
|
+
approval,
|
|
19
|
+
embedding,
|
|
20
|
+
setCurrentExecutionId,
|
|
21
|
+
clearCurrentExecutionId,
|
|
22
|
+
setVectorStoreExecutionId,
|
|
23
|
+
clearVectorStoreExecutionId,
|
|
24
|
+
isPauseError,
|
|
25
|
+
pauseForCallback,
|
|
26
|
+
nextSequenceNumber,
|
|
27
|
+
getCachedResult,
|
|
28
|
+
} from '@mondaydotcomorg/atp-runtime';
|
|
29
|
+
import type { RuntimeContext } from './types.js';
|
|
30
|
+
import {
|
|
31
|
+
createProvenanceProxy,
|
|
32
|
+
getProvenance,
|
|
33
|
+
SecurityPolicyEngine,
|
|
34
|
+
ProvenanceSource,
|
|
35
|
+
registerProvenanceMetadata,
|
|
36
|
+
} from '@mondaydotcomorg/atp-provenance';
|
|
37
|
+
import { ReaderPermissions } from '@mondaydotcomorg/atp-server';
|
|
38
|
+
import { getHintMap, reattachProvenanceFromHints } from '../utils/provenance-reattachment.js';
|
|
39
|
+
import { createASTProvenanceChecker } from './ast-provenance-bridge.js';
|
|
40
|
+
|
|
41
|
+
export class SandboxBuilder {
|
|
42
|
+
private policyEngine: SecurityPolicyEngine | null = null;
|
|
43
|
+
|
|
44
|
+
constructor(private apiGroups: APIGroupConfig[]) {}
|
|
45
|
+
|
|
46
|
+
createSandbox(
|
|
47
|
+
context: RuntimeContext,
|
|
48
|
+
config: ExecutionConfig,
|
|
49
|
+
logger: ReturnType<typeof log.child>,
|
|
50
|
+
executionId: string,
|
|
51
|
+
policyEngine?: SecurityPolicyEngine,
|
|
52
|
+
clientTools?: ClientToolDefinition[]
|
|
53
|
+
): Record<string, unknown> {
|
|
54
|
+
this.policyEngine = policyEngine || null;
|
|
55
|
+
const clientId = context.clientId || 'default';
|
|
56
|
+
|
|
57
|
+
const sandbox: Record<string, unknown> = {
|
|
58
|
+
module: { exports: {} },
|
|
59
|
+
exports: {},
|
|
60
|
+
require: () => {
|
|
61
|
+
throw new Error('require() is not allowed in sandbox');
|
|
62
|
+
},
|
|
63
|
+
|
|
64
|
+
atp: {
|
|
65
|
+
approval: {
|
|
66
|
+
request: async (message: string, approvalContext?: Record<string, unknown>) => {
|
|
67
|
+
context.approvalCallCount++;
|
|
68
|
+
logger.debug('Approval request from sandbox', { message });
|
|
69
|
+
setCurrentExecutionId(executionId);
|
|
70
|
+
try {
|
|
71
|
+
return await approval.request(message, approvalContext);
|
|
72
|
+
} finally {
|
|
73
|
+
clearCurrentExecutionId();
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
llm: {
|
|
78
|
+
call: async (options: {
|
|
79
|
+
prompt: string;
|
|
80
|
+
context?: Record<string, unknown>;
|
|
81
|
+
model?: string;
|
|
82
|
+
temperature?: number;
|
|
83
|
+
systemPrompt?: string;
|
|
84
|
+
}) => {
|
|
85
|
+
if (!config.allowLLMCalls) {
|
|
86
|
+
throw new Error('LLM calls are not allowed in this execution');
|
|
87
|
+
}
|
|
88
|
+
if (++context.llmCallCount > config.maxLLMCalls) {
|
|
89
|
+
throw new Error(`Exceeded max LLM calls: ${config.maxLLMCalls}`);
|
|
90
|
+
}
|
|
91
|
+
logger.debug('LLM call from sandbox', {
|
|
92
|
+
promptLength: options.prompt.length,
|
|
93
|
+
model: options.model,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
if (config.customLLMHandler) {
|
|
97
|
+
return await config.customLLMHandler(options.prompt, options);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
setCurrentExecutionId(executionId);
|
|
101
|
+
try {
|
|
102
|
+
return await llm.call(options);
|
|
103
|
+
} finally {
|
|
104
|
+
clearCurrentExecutionId();
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
extract: async (options: {
|
|
108
|
+
prompt: string;
|
|
109
|
+
schema: unknown;
|
|
110
|
+
context?: Record<string, unknown>;
|
|
111
|
+
}) => {
|
|
112
|
+
if (!config.allowLLMCalls) {
|
|
113
|
+
throw new Error('LLM calls are not allowed in this execution');
|
|
114
|
+
}
|
|
115
|
+
if (++context.llmCallCount > config.maxLLMCalls) {
|
|
116
|
+
throw new Error(`Exceeded max LLM calls: ${config.maxLLMCalls}`);
|
|
117
|
+
}
|
|
118
|
+
logger.debug('LLM extract from sandbox');
|
|
119
|
+
setCurrentExecutionId(executionId);
|
|
120
|
+
try {
|
|
121
|
+
return await llm.extract(options);
|
|
122
|
+
} finally {
|
|
123
|
+
clearCurrentExecutionId();
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
classify: async (options: {
|
|
127
|
+
text: string;
|
|
128
|
+
categories: string[];
|
|
129
|
+
context?: Record<string, unknown>;
|
|
130
|
+
}) => {
|
|
131
|
+
if (!config.allowLLMCalls) {
|
|
132
|
+
throw new Error('LLM calls are not allowed in this execution');
|
|
133
|
+
}
|
|
134
|
+
if (++context.llmCallCount > config.maxLLMCalls) {
|
|
135
|
+
throw new Error(`Exceeded max LLM calls: ${config.maxLLMCalls}`);
|
|
136
|
+
}
|
|
137
|
+
logger.debug('LLM classify from sandbox');
|
|
138
|
+
setCurrentExecutionId(executionId);
|
|
139
|
+
try {
|
|
140
|
+
return await llm.classify(options);
|
|
141
|
+
} finally {
|
|
142
|
+
clearCurrentExecutionId();
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
cache: {
|
|
147
|
+
get: async (key: string) => {
|
|
148
|
+
const scopedKey = `client:${clientId}:cache:${key}`;
|
|
149
|
+
setCurrentExecutionId(executionId);
|
|
150
|
+
try {
|
|
151
|
+
return await cache.get(scopedKey);
|
|
152
|
+
} finally {
|
|
153
|
+
clearCurrentExecutionId();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
set: async (key: string, value: unknown, ttl?: number) => {
|
|
157
|
+
const scopedKey = `client:${clientId}:cache:${key}`;
|
|
158
|
+
setCurrentExecutionId(executionId);
|
|
159
|
+
try {
|
|
160
|
+
return await cache.set(scopedKey, value, ttl);
|
|
161
|
+
} finally {
|
|
162
|
+
clearCurrentExecutionId();
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
delete: async (key: string) => {
|
|
166
|
+
const scopedKey = `client:${clientId}:cache:${key}`;
|
|
167
|
+
setCurrentExecutionId(executionId);
|
|
168
|
+
try {
|
|
169
|
+
return await cache.delete(scopedKey);
|
|
170
|
+
} finally {
|
|
171
|
+
clearCurrentExecutionId();
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
has: async (key: string) => {
|
|
175
|
+
const scopedKey = `client:${clientId}:cache:${key}`;
|
|
176
|
+
setCurrentExecutionId(executionId);
|
|
177
|
+
try {
|
|
178
|
+
return await cache.has(scopedKey);
|
|
179
|
+
} finally {
|
|
180
|
+
clearCurrentExecutionId();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
embedding: {
|
|
185
|
+
embed: async (text: string, options?: Record<string, unknown>) => {
|
|
186
|
+
logger.debug('Embedding request from sandbox', { textLength: text.length });
|
|
187
|
+
setCurrentExecutionId(executionId);
|
|
188
|
+
setVectorStoreExecutionId(executionId);
|
|
189
|
+
try {
|
|
190
|
+
return await embedding.embed(text, options);
|
|
191
|
+
} finally {
|
|
192
|
+
clearCurrentExecutionId();
|
|
193
|
+
clearVectorStoreExecutionId();
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
search: async (query: string, options?: Record<string, unknown>) => {
|
|
197
|
+
logger.debug('Embedding search from sandbox', { query });
|
|
198
|
+
setCurrentExecutionId(executionId);
|
|
199
|
+
setVectorStoreExecutionId(executionId);
|
|
200
|
+
try {
|
|
201
|
+
return await embedding.search(query, options);
|
|
202
|
+
} finally {
|
|
203
|
+
clearCurrentExecutionId();
|
|
204
|
+
clearVectorStoreExecutionId();
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
progress: {
|
|
209
|
+
report: (message: string, fraction: number) => {
|
|
210
|
+
logger.debug('Progress report from sandbox', { message, fraction });
|
|
211
|
+
if (config.progressCallback) {
|
|
212
|
+
config.progressCallback(message, fraction);
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
api: this.createAPIFunctionsWithClientTools(logger, executionId, config, clientTools),
|
|
219
|
+
|
|
220
|
+
console: {
|
|
221
|
+
log: (...args: unknown[]) => {
|
|
222
|
+
const message = args.join(' ');
|
|
223
|
+
logger.debug(`[Sandbox console] ${message}`);
|
|
224
|
+
context.logs.push(`LOG: ${message}`);
|
|
225
|
+
},
|
|
226
|
+
error: (...args: unknown[]) => {
|
|
227
|
+
const message = args.join(' ');
|
|
228
|
+
logger.error(`[Sandbox console] ${message}`);
|
|
229
|
+
context.logs.push(`ERROR: ${message}`);
|
|
230
|
+
},
|
|
231
|
+
warn: (...args: unknown[]) => {
|
|
232
|
+
const message = args.join(' ');
|
|
233
|
+
logger.warn(`[Sandbox console] ${message}`);
|
|
234
|
+
context.logs.push(`WARN: ${message}`);
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
JSON: JSON,
|
|
239
|
+
Math: Math,
|
|
240
|
+
Date: Date,
|
|
241
|
+
Array: Array,
|
|
242
|
+
Object: Object,
|
|
243
|
+
String: String,
|
|
244
|
+
Number: Number,
|
|
245
|
+
Boolean: Boolean,
|
|
246
|
+
Promise: Promise,
|
|
247
|
+
setTimeout: setTimeout,
|
|
248
|
+
setInterval: setInterval,
|
|
249
|
+
clearTimeout: clearTimeout,
|
|
250
|
+
clearInterval: clearInterval,
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
if (
|
|
254
|
+
config.provenanceMode === ProvenanceMode.PROXY ||
|
|
255
|
+
config.provenanceMode === ProvenanceMode.AST
|
|
256
|
+
) {
|
|
257
|
+
sandbox.__getProvenance = getProvenance;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return sandbox;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private createAPIFunctions(
|
|
264
|
+
logger: ReturnType<typeof log.child>,
|
|
265
|
+
executionId: string,
|
|
266
|
+
config: ExecutionConfig
|
|
267
|
+
): Record<string, unknown> {
|
|
268
|
+
const api: Record<string, unknown> = {};
|
|
269
|
+
|
|
270
|
+
for (const group of this.apiGroups) {
|
|
271
|
+
if (group.functions) {
|
|
272
|
+
const groupObj = this.getOrCreateNestedGroup(api, group.name);
|
|
273
|
+
|
|
274
|
+
for (const func of group.functions) {
|
|
275
|
+
const handler = func.handler;
|
|
276
|
+
const metadata = func.metadata;
|
|
277
|
+
|
|
278
|
+
groupObj[func.name] = async (input: unknown) => {
|
|
279
|
+
logger.info(`API function called: ${group.name}.${func.name}`, {
|
|
280
|
+
inputType: typeof input,
|
|
281
|
+
hasMetadata: !!metadata,
|
|
282
|
+
provenanceMode: config.provenanceMode || ProvenanceMode.NONE,
|
|
283
|
+
inputKeys: input && typeof input === 'object' ? Object.keys(input) : [],
|
|
284
|
+
inputPreview: JSON.stringify(input)?.substring(0, 200) || 'undefined',
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// In AST mode, recursively unwrap tainted primitives and register their provenance
|
|
288
|
+
if (
|
|
289
|
+
config.provenanceMode === ProvenanceMode.AST &&
|
|
290
|
+
input &&
|
|
291
|
+
typeof input === 'object'
|
|
292
|
+
) {
|
|
293
|
+
logger.info('Checking for tainted values to unwrap', {
|
|
294
|
+
tool: func.name,
|
|
295
|
+
inputKeys: Object.keys(input),
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
function unwrapTaintedValues(obj: any, visited = new WeakSet<object>()): any {
|
|
299
|
+
if (obj === null || obj === undefined) return obj;
|
|
300
|
+
|
|
301
|
+
// Check if this is a wrapped tainted primitive
|
|
302
|
+
if (typeof obj === 'object' && '__tainted_value' in obj && '__prov_meta' in obj) {
|
|
303
|
+
const taintedVal = obj.__tainted_value;
|
|
304
|
+
const provMeta = obj.__prov_meta;
|
|
305
|
+
|
|
306
|
+
logger.info('FOUND wrapped tainted value!', {
|
|
307
|
+
taintedValType: typeof taintedVal,
|
|
308
|
+
taintedValIsString: typeof taintedVal === 'string',
|
|
309
|
+
taintedValIsNumber: typeof taintedVal === 'number',
|
|
310
|
+
taintedValIsObject: typeof taintedVal === 'object',
|
|
311
|
+
valuePreview:
|
|
312
|
+
typeof taintedVal === 'string' || typeof taintedVal === 'number'
|
|
313
|
+
? String(taintedVal).substring(0, 30)
|
|
314
|
+
: '[OBJECT: ' + Object.keys(taintedVal || {}).join(',') + ']',
|
|
315
|
+
hasProvMeta: !!provMeta,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Register the provenance so host-side checks can find it
|
|
319
|
+
if (provMeta && provMeta.source) {
|
|
320
|
+
registerProvenanceMetadata(
|
|
321
|
+
`tainted:${String(taintedVal)}`,
|
|
322
|
+
{
|
|
323
|
+
id: `tainted:${String(taintedVal)}`,
|
|
324
|
+
source: provMeta.source,
|
|
325
|
+
readers: provMeta.readers || { type: 'public' },
|
|
326
|
+
dependencies: provMeta.deps || provMeta.dependencies || [],
|
|
327
|
+
},
|
|
328
|
+
executionId
|
|
329
|
+
);
|
|
330
|
+
logger.info('Unwrapped and registered tainted primitive', {
|
|
331
|
+
tool: func.name,
|
|
332
|
+
valuePreview: String(taintedVal).substring(0, 30),
|
|
333
|
+
source: provMeta.source?.type,
|
|
334
|
+
executionId: executionId,
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Recursively unwrap in case taintedVal contains more wrapped values
|
|
339
|
+
return unwrapTaintedValues(taintedVal, visited);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Recursively unwrap objects/arrays
|
|
343
|
+
if (typeof obj === 'object') {
|
|
344
|
+
if (visited.has(obj)) return obj;
|
|
345
|
+
visited.add(obj);
|
|
346
|
+
|
|
347
|
+
if (Array.isArray(obj)) {
|
|
348
|
+
return obj.map((item) => unwrapTaintedValues(item, visited));
|
|
349
|
+
} else {
|
|
350
|
+
const unwrapped: Record<string, unknown> = {};
|
|
351
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
352
|
+
unwrapped[key] = unwrapTaintedValues(value, visited);
|
|
353
|
+
}
|
|
354
|
+
return unwrapped;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return obj;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
input = unwrapTaintedValues(input);
|
|
362
|
+
logger.info('After unwrapping', {
|
|
363
|
+
tool: func.name,
|
|
364
|
+
inputPreview: JSON.stringify(input).substring(0, 200),
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Re-attach provenance from hints before policy checks
|
|
369
|
+
const hintMap = getHintMap(executionId);
|
|
370
|
+
if (hintMap && hintMap.size > 0 && input && typeof input === 'object') {
|
|
371
|
+
try {
|
|
372
|
+
reattachProvenanceFromHints(input as Record<string, unknown>, hintMap);
|
|
373
|
+
logger.debug('Provenance re-attached from hints', {
|
|
374
|
+
tool: func.name,
|
|
375
|
+
group: group.name,
|
|
376
|
+
hintsAvailable: hintMap.size,
|
|
377
|
+
});
|
|
378
|
+
} catch (error) {
|
|
379
|
+
logger.warn('Failed to re-attach provenance from hints', { error });
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if (
|
|
384
|
+
this.policyEngine &&
|
|
385
|
+
config.provenanceMode &&
|
|
386
|
+
config.provenanceMode !== ProvenanceMode.NONE
|
|
387
|
+
) {
|
|
388
|
+
logger.debug('Checking security policies', {
|
|
389
|
+
tool: func.name,
|
|
390
|
+
group: group.name,
|
|
391
|
+
hasPolicyEngine: !!this.policyEngine,
|
|
392
|
+
provenanceMode: config.provenanceMode,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
await this.policyEngine.checkTool(
|
|
397
|
+
func.name,
|
|
398
|
+
group.name,
|
|
399
|
+
input as Record<string, unknown>
|
|
400
|
+
);
|
|
401
|
+
logger.debug('Security policies passed', { tool: func.name, group: group.name });
|
|
402
|
+
} catch (error) {
|
|
403
|
+
logger.error('Security policy denied tool execution', {
|
|
404
|
+
tool: func.name,
|
|
405
|
+
group: group.name,
|
|
406
|
+
error: error instanceof Error ? error.message : String(error),
|
|
407
|
+
});
|
|
408
|
+
throw error;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const isDestructive = metadata?.operationType === ToolOperationType.DESTRUCTIVE;
|
|
413
|
+
const isSensitive = metadata?.sensitivityLevel === ToolSensitivityLevel.SENSITIVE;
|
|
414
|
+
const needsApproval = metadata?.requiresApproval || isDestructive || isSensitive;
|
|
415
|
+
|
|
416
|
+
if (needsApproval) {
|
|
417
|
+
let operationDescription = 'operation';
|
|
418
|
+
if (isDestructive) operationDescription = 'destructive operation';
|
|
419
|
+
else if (isSensitive) operationDescription = 'sensitive operation';
|
|
420
|
+
|
|
421
|
+
const approvalMessage = `Approve ${operationDescription}: ${func.name}`;
|
|
422
|
+
|
|
423
|
+
setCurrentExecutionId(executionId);
|
|
424
|
+
try {
|
|
425
|
+
const approvalResult = await approval.request(approvalMessage, {
|
|
426
|
+
tool: func.name,
|
|
427
|
+
group: group.name,
|
|
428
|
+
params: input,
|
|
429
|
+
metadata: metadata,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
if (!approvalResult || !approvalResult.approved) {
|
|
433
|
+
throw new Error(`Operation ${func.name} denied by user`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
logger.info(`Tool approved by user: ${group.name}.${func.name}`, {
|
|
437
|
+
operationType: metadata?.operationType,
|
|
438
|
+
sensitivityLevel: metadata?.sensitivityLevel,
|
|
439
|
+
});
|
|
440
|
+
} catch (error) {
|
|
441
|
+
clearCurrentExecutionId();
|
|
442
|
+
if (isPauseError(error)) {
|
|
443
|
+
throw error;
|
|
444
|
+
}
|
|
445
|
+
throw error;
|
|
446
|
+
}
|
|
447
|
+
clearCurrentExecutionId();
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const result = await handler(input);
|
|
451
|
+
|
|
452
|
+
if (config.provenanceMode === ProvenanceMode.PROXY) {
|
|
453
|
+
let readers: ReaderPermissions = { type: 'public' };
|
|
454
|
+
|
|
455
|
+
if (
|
|
456
|
+
metadata?.sensitivityLevel === ToolSensitivityLevel.SENSITIVE ||
|
|
457
|
+
metadata?.operationType === ToolOperationType.DESTRUCTIVE
|
|
458
|
+
) {
|
|
459
|
+
const inputEmail =
|
|
460
|
+
(input as any)?.email || (input as any)?.user || (input as any)?.userId;
|
|
461
|
+
if (inputEmail && typeof inputEmail === 'string') {
|
|
462
|
+
readers = {
|
|
463
|
+
type: 'restricted',
|
|
464
|
+
readers: [inputEmail],
|
|
465
|
+
};
|
|
466
|
+
} else {
|
|
467
|
+
readers = {
|
|
468
|
+
type: 'restricted',
|
|
469
|
+
readers: [`tool:${func.name}`],
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return createProvenanceProxy(
|
|
475
|
+
result,
|
|
476
|
+
{
|
|
477
|
+
type: ProvenanceSource.TOOL,
|
|
478
|
+
toolName: func.name,
|
|
479
|
+
apiGroup: group.name,
|
|
480
|
+
timestamp: Date.now(),
|
|
481
|
+
},
|
|
482
|
+
readers
|
|
483
|
+
);
|
|
484
|
+
} else if (config.provenanceMode === ProvenanceMode.AST) {
|
|
485
|
+
let readers: ReaderPermissions = { type: 'public' };
|
|
486
|
+
|
|
487
|
+
if (
|
|
488
|
+
metadata?.sensitivityLevel === ToolSensitivityLevel.SENSITIVE ||
|
|
489
|
+
metadata?.operationType === ToolOperationType.DESTRUCTIVE
|
|
490
|
+
) {
|
|
491
|
+
const inputEmail =
|
|
492
|
+
(input as any)?.email || (input as any)?.user || (input as any)?.userId;
|
|
493
|
+
if (inputEmail && typeof inputEmail === 'string') {
|
|
494
|
+
readers = {
|
|
495
|
+
type: 'restricted',
|
|
496
|
+
readers: [inputEmail],
|
|
497
|
+
};
|
|
498
|
+
} else {
|
|
499
|
+
readers = {
|
|
500
|
+
type: 'restricted',
|
|
501
|
+
readers: [`tool:${func.name}`],
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return createProvenanceProxy(
|
|
507
|
+
result,
|
|
508
|
+
{
|
|
509
|
+
type: ProvenanceSource.TOOL,
|
|
510
|
+
toolName: func.name,
|
|
511
|
+
apiGroup: group.name,
|
|
512
|
+
timestamp: Date.now(),
|
|
513
|
+
},
|
|
514
|
+
readers
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return result;
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
return api;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Creates API functions combining both server tools and client tools
|
|
529
|
+
*/
|
|
530
|
+
private createAPIFunctionsWithClientTools(
|
|
531
|
+
logger: ReturnType<typeof log.child>,
|
|
532
|
+
executionId: string,
|
|
533
|
+
config: ExecutionConfig,
|
|
534
|
+
clientTools?: ClientToolDefinition[]
|
|
535
|
+
): Record<string, unknown> {
|
|
536
|
+
const api = this.createAPIFunctions(logger, executionId, config);
|
|
537
|
+
|
|
538
|
+
if (clientTools && clientTools.length > 0) {
|
|
539
|
+
const clientToolFunctions = this.createClientToolFunctions(
|
|
540
|
+
clientTools,
|
|
541
|
+
logger,
|
|
542
|
+
executionId,
|
|
543
|
+
config
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
for (const [namespace, functions] of Object.entries(clientToolFunctions)) {
|
|
547
|
+
if (api[namespace]) {
|
|
548
|
+
Object.assign(api[namespace], functions);
|
|
549
|
+
} else {
|
|
550
|
+
api[namespace] = functions;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
return api;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Creates API functions for client-provided tools that trigger pause/resume
|
|
560
|
+
*/
|
|
561
|
+
private createClientToolFunctions(
|
|
562
|
+
clientTools: ClientToolDefinition[],
|
|
563
|
+
logger: ReturnType<typeof log.child>,
|
|
564
|
+
executionId: string,
|
|
565
|
+
config: ExecutionConfig
|
|
566
|
+
): Record<string, Record<string, unknown>> {
|
|
567
|
+
const api: Record<string, Record<string, unknown>> = {};
|
|
568
|
+
|
|
569
|
+
for (const tool of clientTools) {
|
|
570
|
+
const namespace = tool.namespace || 'client';
|
|
571
|
+
|
|
572
|
+
if (!api[namespace]) {
|
|
573
|
+
api[namespace] = {};
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
const toolName = tool.name;
|
|
577
|
+
const metadata = tool.metadata;
|
|
578
|
+
const provenanceMode = config.provenanceMode || ProvenanceMode.NONE;
|
|
579
|
+
const policyEngine = this.policyEngine;
|
|
580
|
+
|
|
581
|
+
api[namespace][toolName] = async (input: unknown) => {
|
|
582
|
+
setCurrentExecutionId(executionId);
|
|
583
|
+
|
|
584
|
+
try {
|
|
585
|
+
const currentSequence = nextSequenceNumber();
|
|
586
|
+
|
|
587
|
+
const cachedResult = getCachedResult(currentSequence);
|
|
588
|
+
if (cachedResult !== undefined) {
|
|
589
|
+
if (cachedResult && typeof cachedResult === 'object' && (cachedResult as any).__error) {
|
|
590
|
+
throw new Error((cachedResult as any).message);
|
|
591
|
+
}
|
|
592
|
+
return cachedResult;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// Re-attach provenance from hints before policy checks
|
|
596
|
+
const hintMap = getHintMap(executionId);
|
|
597
|
+
if (hintMap && hintMap.size > 0 && input && typeof input === 'object') {
|
|
598
|
+
try {
|
|
599
|
+
reattachProvenanceFromHints(input as Record<string, unknown>, hintMap);
|
|
600
|
+
} catch (error) {
|
|
601
|
+
// Silent fail - re-attachment is best-effort
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (policyEngine && provenanceMode !== ProvenanceMode.NONE) {
|
|
606
|
+
await policyEngine.checkTool(toolName, namespace, input as Record<string, unknown>);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (metadata) {
|
|
610
|
+
const isDestructive = metadata.operationType === ToolOperationType.DESTRUCTIVE;
|
|
611
|
+
const isSensitive = metadata.sensitivityLevel === ToolSensitivityLevel.SENSITIVE;
|
|
612
|
+
const needsApproval = metadata.requiresApproval || isDestructive || isSensitive;
|
|
613
|
+
|
|
614
|
+
if (needsApproval) {
|
|
615
|
+
const operationDescription = isDestructive
|
|
616
|
+
? 'destructive operation'
|
|
617
|
+
: isSensitive
|
|
618
|
+
? 'sensitive operation'
|
|
619
|
+
: 'operation';
|
|
620
|
+
const approvalMessage = `Approve client tool ${operationDescription}: ${toolName}`;
|
|
621
|
+
|
|
622
|
+
const approvalResult = await approval.request(approvalMessage, {
|
|
623
|
+
tool: toolName,
|
|
624
|
+
namespace,
|
|
625
|
+
params: input,
|
|
626
|
+
metadata: metadata,
|
|
627
|
+
isClientTool: true,
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
if (!approvalResult || !approvalResult.approved) {
|
|
631
|
+
throw new Error(`Client tool ${toolName} denied by user`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
pauseForCallback(CallbackType.TOOL, ToolOperation.CALL, {
|
|
637
|
+
toolName,
|
|
638
|
+
namespace,
|
|
639
|
+
input,
|
|
640
|
+
sequenceNumber: currentSequence,
|
|
641
|
+
});
|
|
642
|
+
|
|
643
|
+
throw new Error('Tool execution should have paused');
|
|
644
|
+
} finally {
|
|
645
|
+
clearCurrentExecutionId();
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
return api;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Get or create nested group object from hierarchical path.
|
|
655
|
+
* Supports hierarchical group names like "github/readOnly/repos"
|
|
656
|
+
* Creates nested structure: api.github.readOnly.repos
|
|
657
|
+
* @param api - Root API object
|
|
658
|
+
* @param groupName - Group name (may contain / for hierarchy)
|
|
659
|
+
* @returns The deepest nested object for the group
|
|
660
|
+
*/
|
|
661
|
+
private getOrCreateNestedGroup(
|
|
662
|
+
api: Record<string, unknown>,
|
|
663
|
+
groupName: string
|
|
664
|
+
): Record<string, unknown> {
|
|
665
|
+
if (!groupName.includes('/')) {
|
|
666
|
+
if (!api[groupName]) {
|
|
667
|
+
api[groupName] = {};
|
|
668
|
+
}
|
|
669
|
+
return api[groupName] as Record<string, unknown>;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const parts = groupName.split('/');
|
|
673
|
+
let current = api;
|
|
674
|
+
|
|
675
|
+
for (const part of parts) {
|
|
676
|
+
if (!current[part]) {
|
|
677
|
+
current[part] = {};
|
|
678
|
+
}
|
|
679
|
+
current = current[part] as Record<string, unknown>;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return current;
|
|
683
|
+
}
|
|
684
|
+
}
|