memeloop 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/dist/browser.cjs +1413 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +3066 -0
- package/dist/browser.d.ts +3066 -0
- package/dist/browser.js +43 -0
- package/dist/chunk-426CJUZP.js +630 -0
- package/dist/chunk-426CJUZP.js.map +1 -0
- package/dist/chunk-44YHBKDL.js +382 -0
- package/dist/chunk-44YHBKDL.js.map +1 -0
- package/dist/chunk-7ZDTB4VZ.js +63 -0
- package/dist/chunk-7ZDTB4VZ.js.map +1 -0
- package/dist/chunk-AZFYDWIN.js +98 -0
- package/dist/chunk-AZFYDWIN.js.map +1 -0
- package/dist/chunk-BGPU4RR7.js +367 -0
- package/dist/chunk-BGPU4RR7.js.map +1 -0
- package/dist/chunk-CCEFAOSH.js +496 -0
- package/dist/chunk-CCEFAOSH.js.map +1 -0
- package/dist/chunk-FWSY5HOA.js +63 -0
- package/dist/chunk-FWSY5HOA.js.map +1 -0
- package/dist/chunk-GYIOMQMY.js +8726 -0
- package/dist/chunk-GYIOMQMY.js.map +1 -0
- package/dist/chunk-HVB2BR3H.js +42 -0
- package/dist/chunk-HVB2BR3H.js.map +1 -0
- package/dist/chunk-K6P63KD4.js +68 -0
- package/dist/chunk-K6P63KD4.js.map +1 -0
- package/dist/chunk-MRKY4HGF.js +205 -0
- package/dist/chunk-MRKY4HGF.js.map +1 -0
- package/dist/chunk-QFHAAIIM.js +2657 -0
- package/dist/chunk-QFHAAIIM.js.map +1 -0
- package/dist/chunk-VZKQX5PP.js +1 -0
- package/dist/chunk-VZKQX5PP.js.map +1 -0
- package/dist/chunk-WAI6BODI.js +175 -0
- package/dist/chunk-WAI6BODI.js.map +1 -0
- package/dist/chunk-XHRBV6I3.js +3637 -0
- package/dist/chunk-XHRBV6I3.js.map +1 -0
- package/dist/chunk-YMNXDNDW.js +798 -0
- package/dist/chunk-YMNXDNDW.js.map +1 -0
- package/dist/conversation.cjs +208 -0
- package/dist/conversation.cjs.map +1 -0
- package/dist/conversation.d.cts +100 -0
- package/dist/conversation.d.ts +100 -0
- package/dist/conversation.js +21 -0
- package/dist/conversation.js.map +1 -0
- package/dist/device-network-portable.cjs +702 -0
- package/dist/device-network-portable.cjs.map +1 -0
- package/dist/device-network-portable.d.cts +110 -0
- package/dist/device-network-portable.d.ts +110 -0
- package/dist/device-network-portable.js +53 -0
- package/dist/device-network-portable.js.map +1 -0
- package/dist/device-network.cjs +906 -0
- package/dist/device-network.cjs.map +1 -0
- package/dist/device-network.d.cts +6 -0
- package/dist/device-network.d.ts +6 -0
- package/dist/device-network.js +59 -0
- package/dist/device-network.js.map +1 -0
- package/dist/fetchProvider-BpcGVSOG.d.cts +91 -0
- package/dist/fetchProvider-Cm0sO4Tl.d.ts +91 -0
- package/dist/index.cjs +27957 -5459
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -1320
- package/dist/index.d.ts +94 -1320
- package/dist/index.js +10576 -2386
- package/dist/index.js.map +1 -1
- package/dist/interface-IrKBFtL1.d.cts +493 -0
- package/dist/interface-IrKBFtL1.d.ts +493 -0
- package/dist/llm-providers.cjs +43 -8
- package/dist/llm-providers.cjs.map +1 -1
- package/dist/llm-providers.d.cts +2 -1
- package/dist/llm-providers.d.ts +2 -1
- package/dist/llm-providers.js +4 -2
- package/dist/llm-providers.js.map +1 -1
- package/dist/loop-api.cjs +5177 -2050
- package/dist/loop-api.cjs.map +1 -1
- package/dist/loop-api.d.cts +11 -5
- package/dist/loop-api.d.ts +11 -5
- package/dist/loop-api.js +84 -49
- package/dist/mobile.cjs +2625 -0
- package/dist/mobile.cjs.map +1 -0
- package/dist/mobile.d.cts +6 -0
- package/dist/mobile.d.ts +6 -0
- package/dist/mobile.js +22 -0
- package/dist/mobile.js.map +1 -0
- package/dist/orchestration-portable-Bsf8YRfp.d.cts +2192 -0
- package/dist/orchestration-portable-Zw0g5tbj.d.ts +2192 -0
- package/dist/orchestration-portable.cjs +9553 -0
- package/dist/orchestration-portable.cjs.map +1 -0
- package/dist/orchestration-portable.d.cts +5 -0
- package/dist/orchestration-portable.d.ts +5 -0
- package/dist/orchestration-portable.js +290 -0
- package/dist/orchestration-portable.js.map +1 -0
- package/dist/pairingInvite-BXPWY3aM.d.cts +149 -0
- package/dist/pairingInvite-Cuz0wuq9.d.ts +149 -0
- package/dist/promptConcat-WTN-uHcz.d.cts +516 -0
- package/dist/promptConcat-deDSWZE3.d.ts +516 -0
- package/dist/providerRegistry-9trr5aoK.d.ts +86 -0
- package/dist/providerRegistry-xk_B1Ekv.d.cts +86 -0
- package/dist/registry-8eztoD_r.d.cts +393 -0
- package/dist/registry-DV24sI-3.d.ts +393 -0
- package/dist/remoteClient-B_spK019.d.ts +87 -0
- package/dist/remoteClient-CBggnRy3.d.cts +87 -0
- package/dist/runtime-SKSXVYIM.js +18 -0
- package/dist/runtime-SKSXVYIM.js.map +1 -0
- package/dist/scriptDeploymentPipeline-BAeo1dPb.d.cts +2463 -0
- package/dist/scriptDeploymentPipeline-DsnT0AG6.d.ts +2463 -0
- package/dist/syncCloudDevices-BEqwgrhD.d.ts +49 -0
- package/dist/syncCloudDevices-Ds_Kcgrv.d.cts +49 -0
- package/dist/types-7pYti-k9.d.cts +255 -0
- package/dist/types-CdFVSntj.d.ts +255 -0
- package/package.json +110 -35
- package/dist/anthropic.cjs +0 -72
- package/dist/anthropic.cjs.map +0 -1
- package/dist/anthropic.d.cts +0 -21
- package/dist/anthropic.d.ts +0 -21
- package/dist/anthropic.js +0 -21
- package/dist/anthropic.js.map +0 -1
- package/dist/azure.cjs +0 -72
- package/dist/azure.cjs.map +0 -1
- package/dist/azure.d.cts +0 -21
- package/dist/azure.d.ts +0 -21
- package/dist/azure.js +0 -21
- package/dist/azure.js.map +0 -1
- package/dist/chunk-3CN7DFBL.js +0 -4894
- package/dist/chunk-3CN7DFBL.js.map +0 -1
- package/dist/chunk-4AZ4D7U5.js +0 -32
- package/dist/chunk-4AZ4D7U5.js.map +0 -1
- package/dist/chunk-6ON4XSOV.js +0 -63
- package/dist/chunk-6ON4XSOV.js.map +0 -1
- package/dist/chunk-DJQNGIXX.js +0 -4793
- package/dist/chunk-DJQNGIXX.js.map +0 -1
- package/dist/chunk-FKQP6AOQ.js +0 -32
- package/dist/chunk-FKQP6AOQ.js.map +0 -1
- package/dist/chunk-OVJ7JJBA.js +0 -35
- package/dist/chunk-OVJ7JJBA.js.map +0 -1
- package/dist/chunk-P4UZ7IXC.js +0 -42
- package/dist/chunk-YHJ2AEFR.js +0 -4933
- package/dist/chunk-YHJ2AEFR.js.map +0 -1
- package/dist/chunk-YVK7RYRO.js +0 -4973
- package/dist/chunk-YVK7RYRO.js.map +0 -1
- package/dist/code-assistant.json +0 -114
- package/dist/cohere.cjs +0 -72
- package/dist/cohere.cjs.map +0 -1
- package/dist/cohere.d.cts +0 -21
- package/dist/cohere.d.ts +0 -21
- package/dist/cohere.js +0 -21
- package/dist/cohere.js.map +0 -1
- package/dist/deepseek.cjs +0 -72
- package/dist/deepseek.cjs.map +0 -1
- package/dist/deepseek.d.cts +0 -21
- package/dist/deepseek.d.ts +0 -21
- package/dist/deepseek.js +0 -21
- package/dist/deepseek.js.map +0 -1
- package/dist/dist-65U7OYRG.js +0 -1257
- package/dist/dist-65U7OYRG.js.map +0 -1
- package/dist/fetchProvider-Cu4WkU5O.d.cts +0 -819
- package/dist/fetchProvider-Cu4WkU5O.d.ts +0 -819
- package/dist/frontend-ui-ux.json +0 -105
- package/dist/general-assistant.json +0 -95
- package/dist/git-master.json +0 -51
- package/dist/google-vertex.cjs +0 -72
- package/dist/google-vertex.cjs.map +0 -1
- package/dist/google-vertex.d.cts +0 -21
- package/dist/google-vertex.d.ts +0 -21
- package/dist/google-vertex.js +0 -21
- package/dist/google-vertex.js.map +0 -1
- package/dist/google.cjs +0 -72
- package/dist/google.cjs.map +0 -1
- package/dist/google.d.cts +0 -21
- package/dist/google.d.ts +0 -21
- package/dist/google.js +0 -21
- package/dist/google.js.map +0 -1
- package/dist/groq.cjs +0 -72
- package/dist/groq.cjs.map +0 -1
- package/dist/groq.d.cts +0 -21
- package/dist/groq.d.ts +0 -21
- package/dist/groq.js +0 -21
- package/dist/groq.js.map +0 -1
- package/dist/index.d.mts +0 -3203
- package/dist/index.mjs +0 -7064
- package/dist/index.mjs.map +0 -1
- package/dist/mistral.cjs +0 -72
- package/dist/mistral.cjs.map +0 -1
- package/dist/mistral.d.cts +0 -21
- package/dist/mistral.d.ts +0 -21
- package/dist/mistral.js +0 -21
- package/dist/mistral.js.map +0 -1
- package/dist/multipart-parser-EJCXIUHC.js +0 -372
- package/dist/multipart-parser-EJCXIUHC.js.map +0 -1
- package/dist/openai.cjs +0 -72
- package/dist/openai.cjs.map +0 -1
- package/dist/openai.d.cts +0 -21
- package/dist/openai.d.ts +0 -21
- package/dist/openai.js +0 -21
- package/dist/openai.js.map +0 -1
- package/dist/perplexity.cjs +0 -72
- package/dist/perplexity.cjs.map +0 -1
- package/dist/perplexity.d.cts +0 -21
- package/dist/perplexity.d.ts +0 -21
- package/dist/perplexity.js +0 -21
- package/dist/perplexity.js.map +0 -1
- package/dist/playwright.json +0 -52
- package/dist/promptConcat-BJdazTg5.d.cts +0 -1832
- package/dist/promptConcat-BJdazTg5.d.ts +0 -1832
- package/dist/promptConcat-CAkpni_8.d.cts +0 -1834
- package/dist/promptConcat-CAkpni_8.d.ts +0 -1834
- package/dist/promptConcat-CfH5-GAE.d.cts +0 -1036
- package/dist/promptConcat-ChcAZOOL.d.ts +0 -1036
- package/dist/promptConcat-G5TnJVRy.d.cts +0 -1800
- package/dist/promptConcat-G5TnJVRy.d.ts +0 -1800
- package/dist/promptConcat-L72eowzp.d.ts +0 -1090
- package/dist/promptConcat-eLHdN7K8.d.cts +0 -1090
- package/dist/src-VTSXKG72.js +0 -1409
- package/dist/src-VTSXKG72.js.map +0 -1
- package/dist/togetherai.cjs +0 -72
- package/dist/togetherai.cjs.map +0 -1
- package/dist/togetherai.d.cts +0 -21
- package/dist/togetherai.d.ts +0 -21
- package/dist/togetherai.js +0 -21
- package/dist/togetherai.js.map +0 -1
- package/dist/types-B0Jm2l38.d.cts +0 -767
- package/dist/types-B0Jm2l38.d.ts +0 -767
- package/dist/xai.cjs +0 -72
- package/dist/xai.cjs.map +0 -1
- package/dist/xai.d.cts +0 -21
- package/dist/xai.d.ts +0 -21
- package/dist/xai.js +0 -21
- package/dist/xai.js.map +0 -1
- /package/dist/{chunk-P4UZ7IXC.js.map → browser.js.map} +0 -0
|
@@ -0,0 +1,3637 @@
|
|
|
1
|
+
import {
|
|
2
|
+
containsSecrets
|
|
3
|
+
} from "./chunk-AZFYDWIN.js";
|
|
4
|
+
import {
|
|
5
|
+
MEMELOOP_STRUCTURED_TOOL_KEY,
|
|
6
|
+
createAgentToolLoopRunner,
|
|
7
|
+
createAgentToolLoopState,
|
|
8
|
+
getActivePluginRegistry,
|
|
9
|
+
getBuiltinLoopProfile,
|
|
10
|
+
getLoopRegistry,
|
|
11
|
+
nextLamportClockForConversation,
|
|
12
|
+
runAgentToolLoopIteration,
|
|
13
|
+
startAgentToolLoopTurn,
|
|
14
|
+
stopAgentToolLoopTurn,
|
|
15
|
+
truncateToolSummary
|
|
16
|
+
} from "./chunk-QFHAAIIM.js";
|
|
17
|
+
import {
|
|
18
|
+
AGENT_WORKLOAD_API_VERSION,
|
|
19
|
+
AGENT_WORKLOAD_KIND,
|
|
20
|
+
agentRunReference,
|
|
21
|
+
agentWorkloadReference,
|
|
22
|
+
createAgentRunManifest,
|
|
23
|
+
createAgentWorkloadManifest,
|
|
24
|
+
createArtifactRecordManifest,
|
|
25
|
+
isAgentRun,
|
|
26
|
+
isAgentWorkload
|
|
27
|
+
} from "./chunk-BGPU4RR7.js";
|
|
28
|
+
import {
|
|
29
|
+
OrchestrationError,
|
|
30
|
+
toOrchestrationErrorData
|
|
31
|
+
} from "./chunk-FWSY5HOA.js";
|
|
32
|
+
|
|
33
|
+
// src/orchestration/agentClient.ts
|
|
34
|
+
function requireName(name, generateName, label) {
|
|
35
|
+
if (name) return name;
|
|
36
|
+
if (generateName) return `${generateName}${Math.random().toString(36).slice(2, 8)}`;
|
|
37
|
+
throw new OrchestrationError({ code: "INVALID", message: `${label} requires name or generateName`, retryable: false });
|
|
38
|
+
}
|
|
39
|
+
var CANCELLATION_POLL_INTERVAL_MS = 50;
|
|
40
|
+
function cancellationError(lastResourceVersion) {
|
|
41
|
+
return new OrchestrationError({
|
|
42
|
+
code: "CANCELLED",
|
|
43
|
+
message: "condition wait cancelled",
|
|
44
|
+
retryable: false,
|
|
45
|
+
details: { lastResourceVersion }
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function throwIfCancelled(options, lastResourceVersion) {
|
|
49
|
+
if (options.signal?.aborted || options.isCancelled?.() === true) {
|
|
50
|
+
throw cancellationError(lastResourceVersion);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function abortableDelay(ms, signal, lastResourceVersion) {
|
|
54
|
+
if (!signal) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
setTimeout(resolve, ms);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return new Promise((resolve, reject) => {
|
|
60
|
+
const onAbort = () => {
|
|
61
|
+
clearTimeout(timeout);
|
|
62
|
+
signal.removeEventListener("abort", onAbort);
|
|
63
|
+
reject(cancellationError(lastResourceVersion));
|
|
64
|
+
};
|
|
65
|
+
const timeout = setTimeout(() => {
|
|
66
|
+
signal.removeEventListener("abort", onAbort);
|
|
67
|
+
resolve();
|
|
68
|
+
}, ms);
|
|
69
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
70
|
+
if (signal.aborted) onAbort();
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async function waitInterval(ms, options, lastResourceVersion) {
|
|
74
|
+
if (!options.isCancelled) {
|
|
75
|
+
await abortableDelay(ms, options.signal, lastResourceVersion);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
for (let remaining = ms; remaining > 0; remaining -= CANCELLATION_POLL_INTERVAL_MS) {
|
|
79
|
+
throwIfCancelled(options, lastResourceVersion);
|
|
80
|
+
await abortableDelay(Math.min(remaining, CANCELLATION_POLL_INTERVAL_MS), options.signal, lastResourceVersion);
|
|
81
|
+
}
|
|
82
|
+
throwIfCancelled(options, lastResourceVersion);
|
|
83
|
+
}
|
|
84
|
+
async function waitForCondition(get, condition, options) {
|
|
85
|
+
const intervalMs = Math.max(100, options.interval ?? 1e3);
|
|
86
|
+
const timeoutMs = options.timeout ?? 3e4;
|
|
87
|
+
const deadline = Date.now() + timeoutMs;
|
|
88
|
+
let lastResourceVersion = "0";
|
|
89
|
+
while (true) {
|
|
90
|
+
throwIfCancelled(options, lastResourceVersion);
|
|
91
|
+
const resource = await get();
|
|
92
|
+
throwIfCancelled(options, lastResourceVersion);
|
|
93
|
+
if (resource) {
|
|
94
|
+
lastResourceVersion = resource.metadata?.resourceVersion ?? "0";
|
|
95
|
+
const match = resource.status?.conditions?.find(
|
|
96
|
+
(candidate) => candidate.type === condition.type && candidate.status === condition.status
|
|
97
|
+
);
|
|
98
|
+
if (match) {
|
|
99
|
+
return { observedResourceVersion: lastResourceVersion, matched: true };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (Date.now() + intervalMs > deadline) {
|
|
103
|
+
throw new OrchestrationError({
|
|
104
|
+
code: "TIMEOUT",
|
|
105
|
+
message: `condition ${condition.type}=${condition.status} not met within ${timeoutMs}ms`,
|
|
106
|
+
retryable: true,
|
|
107
|
+
details: { lastResourceVersion }
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
await waitInterval(intervalMs, options, lastResourceVersion);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function createAgentClient(client, defaultNamespace) {
|
|
114
|
+
function resolveNamespace(namespace) {
|
|
115
|
+
return namespace ?? defaultNamespace;
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
async createWorkload(options) {
|
|
119
|
+
const name = requireName(options.name, options.generateName, "AgentWorkload");
|
|
120
|
+
const manifest = createAgentWorkloadManifest(name, {
|
|
121
|
+
profileId: options.profileId,
|
|
122
|
+
scriptReference: options.scriptReference,
|
|
123
|
+
promptReference: options.promptReference,
|
|
124
|
+
trust: options.trust,
|
|
125
|
+
placement: options.placement,
|
|
126
|
+
modelPolicy: options.modelPolicy,
|
|
127
|
+
toolPolicy: options.toolPolicy,
|
|
128
|
+
networkPolicy: options.networkPolicy,
|
|
129
|
+
storagePolicy: options.storagePolicy,
|
|
130
|
+
completionPolicy: options.completionPolicy,
|
|
131
|
+
ownerReferences: options.ownerReferences
|
|
132
|
+
});
|
|
133
|
+
const result = await client.apply(manifest, {
|
|
134
|
+
idempotencyKey: options.idempotencyKey,
|
|
135
|
+
fieldManager: "memeloop-agent-client"
|
|
136
|
+
});
|
|
137
|
+
if (!isAgentWorkload(result)) {
|
|
138
|
+
throw new OrchestrationError({ code: "UNKNOWN_EFFECT", message: "apply returned a non-AgentWorkload resource", retryable: false });
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
},
|
|
142
|
+
async getWorkload(name, namespace) {
|
|
143
|
+
const result = await client.get(agentWorkloadReference(name, resolveNamespace(namespace)));
|
|
144
|
+
return result && isAgentWorkload(result) ? result : null;
|
|
145
|
+
},
|
|
146
|
+
async deleteWorkload(name, namespace) {
|
|
147
|
+
await client.delete(agentWorkloadReference(name, resolveNamespace(namespace)));
|
|
148
|
+
},
|
|
149
|
+
async waitForWorkloadCondition(name, condition, options = {}) {
|
|
150
|
+
return waitForCondition(
|
|
151
|
+
() => this.getWorkload(name, defaultNamespace),
|
|
152
|
+
condition,
|
|
153
|
+
options
|
|
154
|
+
);
|
|
155
|
+
},
|
|
156
|
+
async createRun(options) {
|
|
157
|
+
const name = requireName(options.name, options.generateName, "AgentRun");
|
|
158
|
+
const manifest = createAgentRunManifest(name, {
|
|
159
|
+
workloadRef: agentWorkloadReference(options.workloadName, options.workloadNamespace ?? defaultNamespace),
|
|
160
|
+
promptReference: options.promptReference,
|
|
161
|
+
retry: options.retry,
|
|
162
|
+
timeoutMs: options.timeoutMs
|
|
163
|
+
});
|
|
164
|
+
const result = await client.apply(manifest, {
|
|
165
|
+
idempotencyKey: options.idempotencyKey,
|
|
166
|
+
fieldManager: "memeloop-agent-client"
|
|
167
|
+
});
|
|
168
|
+
if (!isAgentRun(result)) {
|
|
169
|
+
throw new OrchestrationError({ code: "UNKNOWN_EFFECT", message: "apply returned a non-AgentRun resource", retryable: false });
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
},
|
|
173
|
+
async getRun(name, namespace) {
|
|
174
|
+
const result = await client.get(agentRunReference(name, resolveNamespace(namespace)));
|
|
175
|
+
return result && isAgentRun(result) ? result : null;
|
|
176
|
+
},
|
|
177
|
+
async deleteRun(name, namespace) {
|
|
178
|
+
await client.delete(agentRunReference(name, resolveNamespace(namespace)));
|
|
179
|
+
},
|
|
180
|
+
async waitForRunCondition(name, condition, options = {}) {
|
|
181
|
+
return waitForCondition(
|
|
182
|
+
() => this.getRun(name, defaultNamespace),
|
|
183
|
+
condition,
|
|
184
|
+
options
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/tools/schemaRegistry.ts
|
|
191
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
192
|
+
var toolSchemas = /* @__PURE__ */ new Map();
|
|
193
|
+
var toolMetadata = /* @__PURE__ */ new Map();
|
|
194
|
+
function toolSchemaToJsonSchema(value) {
|
|
195
|
+
const native = value?.toJSONSchema?.();
|
|
196
|
+
if (native) return structuredClone(native);
|
|
197
|
+
if (value !== null && typeof value === "object" && "_def" in value) {
|
|
198
|
+
const converted = zodToJsonSchema(value, {
|
|
199
|
+
$refStrategy: "none"
|
|
200
|
+
});
|
|
201
|
+
return structuredClone(converted);
|
|
202
|
+
}
|
|
203
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value) && ("type" in value || "properties" in value || "$ref" in value || "oneOf" in value || "anyOf" in value)) {
|
|
204
|
+
return structuredClone(value);
|
|
205
|
+
}
|
|
206
|
+
throw new TypeError(
|
|
207
|
+
"Tool parameter schema must be a Zod schema or a portable JSON Schema"
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
function registerToolParameterSchema(toolId, schema, metadata) {
|
|
211
|
+
toolSchemas.set(toolId, schema);
|
|
212
|
+
if (metadata) {
|
|
213
|
+
toolMetadata.set(toolId, metadata);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function getToolParameterSchema(toolId) {
|
|
217
|
+
return toolSchemas.get(toolId);
|
|
218
|
+
}
|
|
219
|
+
function getToolMetadata(toolId) {
|
|
220
|
+
return toolMetadata.get(toolId);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/orchestration/scripts/scriptRuntime.ts
|
|
224
|
+
var BUILTIN_RUNTIME_CLASSES = {
|
|
225
|
+
"trusted-process": {
|
|
226
|
+
isolation: "process",
|
|
227
|
+
cpuLimitMillis: 2e3,
|
|
228
|
+
memoryLimitBytes: 512 * 1024 * 1024,
|
|
229
|
+
// 512 MiB
|
|
230
|
+
timeLimitMs: 3e5,
|
|
231
|
+
// 5 min
|
|
232
|
+
supportsCancellation: true,
|
|
233
|
+
supportedTrustClasses: ["trusted"],
|
|
234
|
+
networkAccess: "full"
|
|
235
|
+
},
|
|
236
|
+
"restricted-process": {
|
|
237
|
+
isolation: "process",
|
|
238
|
+
cpuLimitMillis: 1e3,
|
|
239
|
+
memoryLimitBytes: 128 * 1024 * 1024,
|
|
240
|
+
// 128 MiB
|
|
241
|
+
timeLimitMs: 12e4,
|
|
242
|
+
// 2 min
|
|
243
|
+
supportsCancellation: true,
|
|
244
|
+
supportedTrustClasses: ["trusted", "restricted"],
|
|
245
|
+
networkAccess: "outbound-only"
|
|
246
|
+
},
|
|
247
|
+
"quarantine-process": {
|
|
248
|
+
isolation: "process",
|
|
249
|
+
cpuLimitMillis: 500,
|
|
250
|
+
// A Node VM plus the trusted worker bootstrap needs more than 32 MiB RSS;
|
|
251
|
+
// the Linux host enforces this value as cgroup MemoryMax, not only V8 heap.
|
|
252
|
+
memoryLimitBytes: 96 * 1024 * 1024,
|
|
253
|
+
// 96 MiB
|
|
254
|
+
timeLimitMs: 3e4,
|
|
255
|
+
// 30 sec
|
|
256
|
+
supportsCancellation: true,
|
|
257
|
+
supportedTrustClasses: ["quarantine"],
|
|
258
|
+
networkAccess: "none"
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
function selectRuntimeClass(trustClass, available = Object.keys(BUILTIN_RUNTIME_CLASSES)) {
|
|
262
|
+
const exact = available.find((name2) => {
|
|
263
|
+
const spec2 = BUILTIN_RUNTIME_CLASSES[name2];
|
|
264
|
+
return spec2?.supportedTrustClasses.includes(trustClass);
|
|
265
|
+
});
|
|
266
|
+
if (!exact) {
|
|
267
|
+
throw new Error("No RuntimeClass available for trust class: " + trustClass);
|
|
268
|
+
}
|
|
269
|
+
const name = exact;
|
|
270
|
+
const spec = BUILTIN_RUNTIME_CLASSES[name];
|
|
271
|
+
return {
|
|
272
|
+
runtimeClass: name,
|
|
273
|
+
isolation: spec.isolation,
|
|
274
|
+
cpuLimitMillis: spec.cpuLimitMillis ?? 500,
|
|
275
|
+
memoryLimitBytes: spec.memoryLimitBytes ?? 32 * 1024 * 1024,
|
|
276
|
+
timeLimitMs: spec.timeLimitMs ?? 3e4,
|
|
277
|
+
networkAccess: spec.networkAccess
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/orchestration/scripts/scriptAdmission.ts
|
|
282
|
+
var TRUST_PROFILES = {
|
|
283
|
+
trusted: {
|
|
284
|
+
maxScriptBytes: 1048576,
|
|
285
|
+
// 1 MiB
|
|
286
|
+
allowedInterfaces: ["resource", "loop-runtime", "tool-execution", "model-provider", "network", "storage", "credential-broker", "artifact"],
|
|
287
|
+
forbiddenImports: [],
|
|
288
|
+
requireDefaultExport: true,
|
|
289
|
+
allowUntrustedInputs: false
|
|
290
|
+
},
|
|
291
|
+
restricted: {
|
|
292
|
+
maxScriptBytes: 256e3,
|
|
293
|
+
// 256 KiB
|
|
294
|
+
allowedInterfaces: ["resource", "loop-runtime", "model-provider"],
|
|
295
|
+
forbiddenImports: ["node:fs", "node:child_process", "node:net", "node:http", "node:https"],
|
|
296
|
+
requireDefaultExport: true,
|
|
297
|
+
allowUntrustedInputs: false
|
|
298
|
+
},
|
|
299
|
+
quarantine: {
|
|
300
|
+
maxScriptBytes: 64e3,
|
|
301
|
+
// 64 KiB
|
|
302
|
+
allowedInterfaces: ["loop-runtime"],
|
|
303
|
+
// No network, no file system, no model provider
|
|
304
|
+
forbiddenImports: ["node:fs", "node:child_process", "node:net", "node:http", "node:https", "node:os", "node:crypto"],
|
|
305
|
+
requireDefaultExport: true,
|
|
306
|
+
allowUntrustedInputs: false
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
var COMPATIBLE_CHECKPOINT_VERSIONS = /* @__PURE__ */ new Set(["loops.memeloop.io/v1alpha1"]);
|
|
310
|
+
function defaultRequestedInterfacesForTrustClass(trustClass) {
|
|
311
|
+
return [...TRUST_PROFILES[trustClass].allowedInterfaces];
|
|
312
|
+
}
|
|
313
|
+
function maxScriptBytesForTrustClass(trustClass) {
|
|
314
|
+
return TRUST_PROFILES[trustClass].maxScriptBytes;
|
|
315
|
+
}
|
|
316
|
+
function admitScript(request) {
|
|
317
|
+
const profile = TRUST_PROFILES[request.authorTrust];
|
|
318
|
+
const approvedInterfaces = [];
|
|
319
|
+
if (request.script.sizeBytes > profile.maxScriptBytes) {
|
|
320
|
+
return {
|
|
321
|
+
admitted: false,
|
|
322
|
+
reason: `Script size ${request.script.sizeBytes} exceeds ${request.authorTrust} limit ${profile.maxScriptBytes}`,
|
|
323
|
+
approvedInterfaces: [],
|
|
324
|
+
checkpointCompatible: false,
|
|
325
|
+
retryable: true
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
if (!request.script.valid) {
|
|
329
|
+
return {
|
|
330
|
+
admitted: false,
|
|
331
|
+
reason: `Script validation failed: ${request.script.errors.join("; ")}`,
|
|
332
|
+
approvedInterfaces: [],
|
|
333
|
+
checkpointCompatible: false,
|
|
334
|
+
retryable: true
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (profile.requireDefaultExport && !request.script.hasDefaultExport) {
|
|
338
|
+
return {
|
|
339
|
+
admitted: false,
|
|
340
|
+
reason: "Script must export a default async generator",
|
|
341
|
+
approvedInterfaces: [],
|
|
342
|
+
checkpointCompatible: false,
|
|
343
|
+
retryable: true
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
for (const imp of request.script.imports) {
|
|
347
|
+
if (profile.forbiddenImports.includes(imp) || profile.forbiddenImports.includes(imp.replace(/^node:/, ""))) {
|
|
348
|
+
return {
|
|
349
|
+
admitted: false,
|
|
350
|
+
reason: `Import '${imp}' not allowed for ${request.authorTrust} scripts`,
|
|
351
|
+
approvedInterfaces: [],
|
|
352
|
+
checkpointCompatible: false,
|
|
353
|
+
retryable: false
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
for (const iface of request.requestedInterfaces) {
|
|
358
|
+
if (!profile.allowedInterfaces.includes(iface)) {
|
|
359
|
+
return {
|
|
360
|
+
admitted: false,
|
|
361
|
+
reason: `Interface '${iface}' not allowed for ${request.authorTrust} scripts`,
|
|
362
|
+
approvedInterfaces: [],
|
|
363
|
+
checkpointCompatible: false,
|
|
364
|
+
retryable: false
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
approvedInterfaces.push(iface);
|
|
368
|
+
}
|
|
369
|
+
let checkpointCompatible = true;
|
|
370
|
+
if (request.expectedCheckpointDigest && request.checkpointApiVersion) {
|
|
371
|
+
if (!COMPATIBLE_CHECKPOINT_VERSIONS.has(request.checkpointApiVersion)) {
|
|
372
|
+
checkpointCompatible = false;
|
|
373
|
+
}
|
|
374
|
+
if (request.expectedCheckpointDigest !== request.script.digest) {
|
|
375
|
+
checkpointCompatible = false;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return {
|
|
379
|
+
admitted: true,
|
|
380
|
+
reason: `Admitted as ${request.authorTrust}`,
|
|
381
|
+
approvedInterfaces,
|
|
382
|
+
checkpointCompatible,
|
|
383
|
+
retryable: false
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/orchestration/scripts/scriptValidation.ts
|
|
388
|
+
import { parse } from "acorn";
|
|
389
|
+
var MAX_SCRIPT_BYTES = 1048576;
|
|
390
|
+
function isAstNode(value) {
|
|
391
|
+
return typeof value === "object" && value !== null && typeof value.type === "string";
|
|
392
|
+
}
|
|
393
|
+
function walkAst(node, visit) {
|
|
394
|
+
visit(node);
|
|
395
|
+
for (const key of Object.keys(node)) {
|
|
396
|
+
const value = node[key];
|
|
397
|
+
if (Array.isArray(value)) {
|
|
398
|
+
for (const child of value) {
|
|
399
|
+
if (isAstNode(child)) walkAst(child, visit);
|
|
400
|
+
}
|
|
401
|
+
} else if (isAstNode(value)) {
|
|
402
|
+
walkAst(value, visit);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function isAsyncGeneratorFunction(node) {
|
|
407
|
+
if (!node) return false;
|
|
408
|
+
return (node.type === "FunctionDeclaration" || node.type === "FunctionExpression") && node.async === true && node.generator === true;
|
|
409
|
+
}
|
|
410
|
+
function getStaticImportSource(node) {
|
|
411
|
+
const source = node.source;
|
|
412
|
+
if (source && source.type === "Literal" && typeof source.value === "string") {
|
|
413
|
+
return source.value;
|
|
414
|
+
}
|
|
415
|
+
return void 0;
|
|
416
|
+
}
|
|
417
|
+
function isCommonJsExportAssignment(node) {
|
|
418
|
+
if (node.type !== "AssignmentExpression") return false;
|
|
419
|
+
const left = node.left;
|
|
420
|
+
if (!left || left.type !== "MemberExpression" || left.computed === true) return false;
|
|
421
|
+
const object = left.object;
|
|
422
|
+
const property = left.property;
|
|
423
|
+
if (!object || object.type !== "Identifier" || !property || property.type !== "Identifier") {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (object.name === "exports") return true;
|
|
427
|
+
return object.name === "module" && property.name === "exports";
|
|
428
|
+
}
|
|
429
|
+
async function digestNormalizedScript(normalizedSource) {
|
|
430
|
+
const encoded = new TextEncoder().encode(normalizedSource);
|
|
431
|
+
const hash = await crypto.subtle.digest("SHA-256", encoded);
|
|
432
|
+
return Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
433
|
+
}
|
|
434
|
+
async function validateScript(source) {
|
|
435
|
+
const errors = [];
|
|
436
|
+
const imports = [];
|
|
437
|
+
let hasDefaultExport = false;
|
|
438
|
+
let hasNonLiteralDynamicImport = false;
|
|
439
|
+
const normalized = normalizeScript(source);
|
|
440
|
+
const encoded = new TextEncoder().encode(normalized);
|
|
441
|
+
if (encoded.length > MAX_SCRIPT_BYTES) {
|
|
442
|
+
errors.push(`Script exceeds ${MAX_SCRIPT_BYTES} bytes (got ${encoded.length})`);
|
|
443
|
+
}
|
|
444
|
+
if (normalized.trim().length === 0) {
|
|
445
|
+
errors.push("Script is empty");
|
|
446
|
+
}
|
|
447
|
+
const digest = await digestNormalizedScript(normalized);
|
|
448
|
+
let program;
|
|
449
|
+
if (normalized.trim().length > 0) {
|
|
450
|
+
try {
|
|
451
|
+
program = parse(normalized, { ecmaVersion: "latest", sourceType: "module" });
|
|
452
|
+
} catch (error) {
|
|
453
|
+
errors.push(`Syntax error: ${error instanceof Error ? error.message : String(error)}`);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (program) {
|
|
457
|
+
const topLevel = Array.isArray(program.body) ? program.body : [];
|
|
458
|
+
for (const statement of topLevel) {
|
|
459
|
+
if (statement.type !== "ExportDefaultDeclaration") continue;
|
|
460
|
+
const declaration = statement.declaration;
|
|
461
|
+
if (isAsyncGeneratorFunction(declaration)) {
|
|
462
|
+
hasDefaultExport = true;
|
|
463
|
+
} else if (declaration?.type === "Identifier") {
|
|
464
|
+
const identifier = declaration;
|
|
465
|
+
hasDefaultExport = topLevel.some((candidate) => {
|
|
466
|
+
if (isAsyncGeneratorFunction(candidate) && candidate.id?.name === identifier.name) {
|
|
467
|
+
return true;
|
|
468
|
+
}
|
|
469
|
+
if (candidate.type === "VariableDeclaration" && Array.isArray(candidate.declarations)) {
|
|
470
|
+
return candidate.declarations.some(
|
|
471
|
+
(declarator) => declarator.id?.name === identifier.name && isAsyncGeneratorFunction(declarator.init)
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
return false;
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
walkAst(program, (node) => {
|
|
479
|
+
if (node.type === "ImportDeclaration") {
|
|
480
|
+
const specifier = getStaticImportSource(node);
|
|
481
|
+
if (specifier !== void 0) imports.push(specifier);
|
|
482
|
+
} else if (node.type === "ExportNamedDeclaration" || node.type === "ExportAllDeclaration") {
|
|
483
|
+
const specifier = getStaticImportSource(node);
|
|
484
|
+
if (specifier !== void 0) imports.push(specifier);
|
|
485
|
+
} else if (node.type === "ImportExpression") {
|
|
486
|
+
const specifier = getStaticImportSource(node);
|
|
487
|
+
if (specifier !== void 0) {
|
|
488
|
+
imports.push(specifier);
|
|
489
|
+
} else {
|
|
490
|
+
hasNonLiteralDynamicImport = true;
|
|
491
|
+
}
|
|
492
|
+
} else if (isCommonJsExportAssignment(node)) {
|
|
493
|
+
errors.push("CommonJS module.exports not supported (use ESM export)");
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
for (const specifier of imports) {
|
|
498
|
+
if (isForbiddenImport(specifier)) {
|
|
499
|
+
errors.push(`Forbidden import: ${specifier}`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
if (hasNonLiteralDynamicImport) {
|
|
503
|
+
errors.push("Dynamic import() with a non-literal argument is not allowed (defeats admission control)");
|
|
504
|
+
}
|
|
505
|
+
if (!hasDefaultExport) {
|
|
506
|
+
errors.push("Script must export a default async generator function");
|
|
507
|
+
}
|
|
508
|
+
return {
|
|
509
|
+
valid: errors.length === 0,
|
|
510
|
+
digest,
|
|
511
|
+
imports,
|
|
512
|
+
hasDefaultExport,
|
|
513
|
+
hasNonLiteralDynamicImport,
|
|
514
|
+
errors,
|
|
515
|
+
sizeBytes: encoded.length
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
function normalizeScript(source) {
|
|
519
|
+
return source.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n").map((line) => line.trimEnd()).join("\n").trim() + "\n";
|
|
520
|
+
}
|
|
521
|
+
function isForbiddenImport(spec) {
|
|
522
|
+
const builtins = /* @__PURE__ */ new Set([
|
|
523
|
+
"fs",
|
|
524
|
+
"path",
|
|
525
|
+
"child_process",
|
|
526
|
+
"net",
|
|
527
|
+
"http",
|
|
528
|
+
"https",
|
|
529
|
+
"os",
|
|
530
|
+
"crypto",
|
|
531
|
+
"tls",
|
|
532
|
+
"dgram",
|
|
533
|
+
"dns",
|
|
534
|
+
"readline",
|
|
535
|
+
"repl",
|
|
536
|
+
"stream",
|
|
537
|
+
"timers",
|
|
538
|
+
"tty",
|
|
539
|
+
"url",
|
|
540
|
+
"util",
|
|
541
|
+
"v8",
|
|
542
|
+
"vm",
|
|
543
|
+
"worker_threads",
|
|
544
|
+
"zlib",
|
|
545
|
+
"assert",
|
|
546
|
+
"buffer",
|
|
547
|
+
"querystring",
|
|
548
|
+
"string_decoder"
|
|
549
|
+
]);
|
|
550
|
+
const base = spec.replace(/^node:/, "");
|
|
551
|
+
if (builtins.has(base) && spec !== "node:events") return true;
|
|
552
|
+
if (spec.startsWith("@libp2p/") || spec.startsWith("@chainsafe/libp2p") || spec === "libp2p") {
|
|
553
|
+
return true;
|
|
554
|
+
}
|
|
555
|
+
if (spec === "memeloop" || spec.startsWith("memeloop/")) return true;
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/orchestration/scripts/scriptDeploymentPipeline.ts
|
|
560
|
+
var LIFECYCLE_TO_COMPLETION_POLICY = {
|
|
561
|
+
"run-once": "complete",
|
|
562
|
+
service: "daemon",
|
|
563
|
+
schedule: "detach"
|
|
564
|
+
};
|
|
565
|
+
function remoteDeploymentToWorkloadManifest(deployment, options = {}) {
|
|
566
|
+
const manifest = createAgentWorkloadManifest(options.name ?? deployment.artifactRef.name, {
|
|
567
|
+
scriptReference: deployment.artifactRef.contentDigest,
|
|
568
|
+
trust: deployment.trustClass,
|
|
569
|
+
runtimeClass: deployment.runtimeClass,
|
|
570
|
+
completionPolicy: LIFECYCLE_TO_COMPLETION_POLICY[deployment.lifecycle],
|
|
571
|
+
...deployment.nodeSelector ? { placement: { nodeSelector: deployment.nodeSelector } } : {},
|
|
572
|
+
...deployment.env ? { env: deployment.env } : {},
|
|
573
|
+
...deployment.networkPolicy ? { networkPolicy: deployment.networkPolicy } : {},
|
|
574
|
+
...deployment.storagePolicy ? { storagePolicy: deployment.storagePolicy } : {},
|
|
575
|
+
...options.ownerReferences ? { ownerReferences: options.ownerReferences } : {}
|
|
576
|
+
});
|
|
577
|
+
const namespace = options.namespace ?? deployment.artifactRef.namespace;
|
|
578
|
+
if (namespace !== void 0) {
|
|
579
|
+
manifest.metadata.namespace = namespace;
|
|
580
|
+
}
|
|
581
|
+
return manifest;
|
|
582
|
+
}
|
|
583
|
+
async function deployGeneratedScript(request, options = {}) {
|
|
584
|
+
const validation = await validateScript(request.source);
|
|
585
|
+
if (!validation.valid) {
|
|
586
|
+
return {
|
|
587
|
+
deployed: false,
|
|
588
|
+
reason: `Script validation failed: ${validation.errors.join("; ")}`,
|
|
589
|
+
validation
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
const admission = admitScript({
|
|
593
|
+
script: validation,
|
|
594
|
+
authorTrust: request.authorTrust,
|
|
595
|
+
requestedInterfaces: request.requestedInterfaces,
|
|
596
|
+
expectedCheckpointDigest: request.expectedCheckpointDigest,
|
|
597
|
+
checkpointApiVersion: request.checkpointApiVersion
|
|
598
|
+
});
|
|
599
|
+
if (!admission.admitted) {
|
|
600
|
+
return { deployed: false, reason: admission.reason, validation, admission };
|
|
601
|
+
}
|
|
602
|
+
if (request.expectedCheckpointDigest !== void 0 && !admission.checkpointCompatible) {
|
|
603
|
+
return {
|
|
604
|
+
deployed: false,
|
|
605
|
+
reason: "Checkpoint is incompatible with this script digest/API version; an explicit converter or restart policy is required",
|
|
606
|
+
validation,
|
|
607
|
+
admission
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
for (const [name, value] of Object.entries(request.env ?? {})) {
|
|
611
|
+
if (containsSecrets(value)) {
|
|
612
|
+
return {
|
|
613
|
+
deployed: false,
|
|
614
|
+
reason: `Environment variable '${name}' carries a secret-shaped value; workload env must never contain credentials (plan 24.35)`,
|
|
615
|
+
validation,
|
|
616
|
+
admission
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
const contentDigest = `sha256:${validation.digest}`;
|
|
621
|
+
const artifactName = `script-${validation.digest}`;
|
|
622
|
+
const artifact = createArtifactRecordManifest(artifactName, {
|
|
623
|
+
contentHash: contentDigest,
|
|
624
|
+
sizeBytes: validation.sizeBytes,
|
|
625
|
+
mimeType: "text/javascript",
|
|
626
|
+
producer: { trust: request.authorTrust },
|
|
627
|
+
trust: request.authorTrust
|
|
628
|
+
});
|
|
629
|
+
if (request.namespace !== void 0) {
|
|
630
|
+
artifact.metadata.namespace = request.namespace;
|
|
631
|
+
}
|
|
632
|
+
await options.artifactStore?.putArtifact(artifact, normalizeScript(request.source));
|
|
633
|
+
const runtimeClass = selectRuntimeClass(request.authorTrust, options.availableRuntimeClasses);
|
|
634
|
+
const deployment = {
|
|
635
|
+
artifactRef: {
|
|
636
|
+
apiVersion: artifact.apiVersion,
|
|
637
|
+
kind: "ArtifactRecord",
|
|
638
|
+
name: artifactName,
|
|
639
|
+
namespace: artifact.metadata.namespace,
|
|
640
|
+
contentDigest
|
|
641
|
+
},
|
|
642
|
+
trustClass: request.authorTrust,
|
|
643
|
+
lifecycle: request.lifecycle,
|
|
644
|
+
runtimeClass: runtimeClass.runtimeClass,
|
|
645
|
+
nodeSelector: request.nodeSelector,
|
|
646
|
+
env: request.env,
|
|
647
|
+
networkPolicy: request.networkPolicy,
|
|
648
|
+
storagePolicy: request.storagePolicy
|
|
649
|
+
};
|
|
650
|
+
return {
|
|
651
|
+
deployed: true,
|
|
652
|
+
reason: admission.reason,
|
|
653
|
+
validation,
|
|
654
|
+
admission,
|
|
655
|
+
artifact,
|
|
656
|
+
runtimeClass,
|
|
657
|
+
deployment
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function createScriptLoadGate(config) {
|
|
661
|
+
return {
|
|
662
|
+
async admitScriptLoad(request) {
|
|
663
|
+
const validation = await validateScript(request.normalizedSource);
|
|
664
|
+
if (!validation.valid) {
|
|
665
|
+
return { allowed: false, reason: `Script validation failed: ${validation.errors.join("; ")}` };
|
|
666
|
+
}
|
|
667
|
+
if (validation.digest !== request.digest) {
|
|
668
|
+
return { allowed: false, reason: "Digest mismatch between loader and validated source" };
|
|
669
|
+
}
|
|
670
|
+
const admission = admitScript({
|
|
671
|
+
script: validation,
|
|
672
|
+
authorTrust: config.authorTrust,
|
|
673
|
+
requestedInterfaces: config.requestedInterfaces,
|
|
674
|
+
expectedCheckpointDigest: config.expectedCheckpointDigest,
|
|
675
|
+
checkpointApiVersion: config.checkpointApiVersion
|
|
676
|
+
});
|
|
677
|
+
if (!admission.admitted) {
|
|
678
|
+
return { allowed: false, reason: admission.reason };
|
|
679
|
+
}
|
|
680
|
+
if (config.expectedCheckpointDigest !== void 0 && !admission.checkpointCompatible) {
|
|
681
|
+
return {
|
|
682
|
+
allowed: false,
|
|
683
|
+
reason: "Checkpoint is incompatible with this script digest/API version; an explicit converter or restart policy is required"
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
const runtimeClass = selectRuntimeClass(config.authorTrust, config.availableRuntimeClasses);
|
|
687
|
+
return {
|
|
688
|
+
allowed: true,
|
|
689
|
+
trustClass: config.authorTrust,
|
|
690
|
+
runtimeClass: runtimeClass.runtimeClass,
|
|
691
|
+
checkpointCompatible: admission.checkpointCompatible
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function createScriptDeploymentClient(config) {
|
|
697
|
+
const interfaceCeiling = config.requestedInterfaces ?? defaultRequestedInterfacesForTrustClass(config.authorTrust);
|
|
698
|
+
function requireOrchestration() {
|
|
699
|
+
if (!config.orchestration) {
|
|
700
|
+
throw new OrchestrationError({
|
|
701
|
+
code: "UNSUPPORTED",
|
|
702
|
+
message: "script deployment scheduling requires a host-configured orchestration facade",
|
|
703
|
+
retryable: false
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
return config.orchestration;
|
|
707
|
+
}
|
|
708
|
+
return {
|
|
709
|
+
async deploy(request) {
|
|
710
|
+
const result = await deployGeneratedScript(
|
|
711
|
+
{
|
|
712
|
+
source: request.source,
|
|
713
|
+
authorTrust: config.authorTrust,
|
|
714
|
+
requestedInterfaces: request.requestedInterfaces ?? interfaceCeiling,
|
|
715
|
+
lifecycle: request.lifecycle,
|
|
716
|
+
nodeSelector: request.nodeSelector,
|
|
717
|
+
env: request.env,
|
|
718
|
+
networkPolicy: request.networkPolicy,
|
|
719
|
+
storagePolicy: request.storagePolicy,
|
|
720
|
+
expectedCheckpointDigest: request.expectedCheckpointDigest,
|
|
721
|
+
checkpointApiVersion: request.checkpointApiVersion,
|
|
722
|
+
namespace: request.namespace ?? config.namespace
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
artifactStore: config.artifactStore,
|
|
726
|
+
availableRuntimeClasses: config.availableRuntimeClasses
|
|
727
|
+
}
|
|
728
|
+
);
|
|
729
|
+
if (result.deployed && result.deployment && config.orchestration) {
|
|
730
|
+
const manifest = remoteDeploymentToWorkloadManifest(result.deployment, {
|
|
731
|
+
namespace: request.namespace ?? config.namespace
|
|
732
|
+
});
|
|
733
|
+
const workload = await config.orchestration.apply(manifest, {
|
|
734
|
+
idempotencyKey: result.deployment.artifactRef.contentDigest,
|
|
735
|
+
fieldManager: config.fieldManager ?? "memeloop/script-deployment"
|
|
736
|
+
});
|
|
737
|
+
return { ...result, workload };
|
|
738
|
+
}
|
|
739
|
+
return result;
|
|
740
|
+
},
|
|
741
|
+
async waitForScheduled(name, options = {}) {
|
|
742
|
+
const orchestration = requireOrchestration();
|
|
743
|
+
const { namespace, ...waitOptions2 } = options;
|
|
744
|
+
return waitForCondition(
|
|
745
|
+
() => orchestration.get({
|
|
746
|
+
apiVersion: AGENT_WORKLOAD_API_VERSION,
|
|
747
|
+
kind: AGENT_WORKLOAD_KIND,
|
|
748
|
+
name,
|
|
749
|
+
namespace: namespace ?? config.namespace
|
|
750
|
+
}),
|
|
751
|
+
{ type: "Scheduled", status: "True" },
|
|
752
|
+
waitOptions2
|
|
753
|
+
);
|
|
754
|
+
},
|
|
755
|
+
async deleteDeployment(name, namespace) {
|
|
756
|
+
const orchestration = requireOrchestration();
|
|
757
|
+
await orchestration.delete({
|
|
758
|
+
apiVersion: AGENT_WORKLOAD_API_VERSION,
|
|
759
|
+
kind: AGENT_WORKLOAD_KIND,
|
|
760
|
+
name,
|
|
761
|
+
namespace: namespace ?? config.namespace
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// src/loops/agent-agent-loop/builtinLoopSources.ts
|
|
768
|
+
var AgentAgentLoopArtifactResourceLifecycleScriptId = "builtin:agent-agent-loop/artifact-resource-lifecycle";
|
|
769
|
+
var AgentAgentLoopDeclarativeAgentRunScriptId = "builtin:agent-agent-loop/declarative-agent-run";
|
|
770
|
+
var AgentAgentLoopQualityGateScriptId = "builtin:agent-agent-loop/quality-gate";
|
|
771
|
+
var BUILTIN_AGENT_AGENT_LOOP_ARTIFACT_RESOURCE_LIFECYCLE_SCRIPT_ID = AgentAgentLoopArtifactResourceLifecycleScriptId;
|
|
772
|
+
var BUILTIN_AGENT_AGENT_LOOP_DECLARATIVE_AGENT_RUN_SCRIPT_ID = AgentAgentLoopDeclarativeAgentRunScriptId;
|
|
773
|
+
var BUILTIN_AGENT_AGENT_LOOP_QUALITY_GATE_SCRIPT_ID = AgentAgentLoopQualityGateScriptId;
|
|
774
|
+
var builtinAgentAgentLoopSources = {
|
|
775
|
+
[AgentAgentLoopArtifactResourceLifecycleScriptId]: [
|
|
776
|
+
"// @ts-check",
|
|
777
|
+
"",
|
|
778
|
+
"function resourceName(value) {",
|
|
779
|
+
' const normalized = value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");',
|
|
780
|
+
' return (normalized || "artifact").slice(0, 56);',
|
|
781
|
+
"}",
|
|
782
|
+
"",
|
|
783
|
+
"/** @param {import('../../loopAPI/agent-agent-loop/loop.js').AgentAgentScriptContext} ctx */",
|
|
784
|
+
"export default async function run(ctx) {",
|
|
785
|
+
" if (!ctx.orchestration) {",
|
|
786
|
+
' throw new Error("artifact-resource-lifecycle requires the orchestration resource facade");',
|
|
787
|
+
" }",
|
|
788
|
+
"",
|
|
789
|
+
" const metadata = ctx.profile?.metadata ?? {};",
|
|
790
|
+
' const contentHash = typeof metadata.contentHash === "string"',
|
|
791
|
+
" ? metadata.contentHash",
|
|
792
|
+
' : "sha256:0000000000000000000000000000000000000000000000000000000000000000";',
|
|
793
|
+
" const artifactName = resourceName(`script-${ctx.input.conversationId}`);",
|
|
794
|
+
" const query = {",
|
|
795
|
+
' apiVersion: "artifacts.memeloop.io/v1alpha1",',
|
|
796
|
+
' kind: "ArtifactRecord",',
|
|
797
|
+
' namespace: "default",',
|
|
798
|
+
" };",
|
|
799
|
+
" const abortController = new AbortController();",
|
|
800
|
+
" const events = ctx.orchestration.watch(query, {",
|
|
801
|
+
' resourceVersion: "0",',
|
|
802
|
+
" sendInitialEvents: true,",
|
|
803
|
+
" allowBookmarks: true,",
|
|
804
|
+
" timeoutMs: 5_000,",
|
|
805
|
+
" signal: abortController.signal,",
|
|
806
|
+
" })[Symbol.asyncIterator]();",
|
|
807
|
+
" const nextEvent = events.next();",
|
|
808
|
+
"",
|
|
809
|
+
" try {",
|
|
810
|
+
" const artifact = await ctx.orchestration.apply({",
|
|
811
|
+
" apiVersion: query.apiVersion,",
|
|
812
|
+
" kind: query.kind,",
|
|
813
|
+
" metadata: {",
|
|
814
|
+
" name: artifactName,",
|
|
815
|
+
" namespace: query.namespace,",
|
|
816
|
+
' labels: { "memeloop.io/artifact-purpose": "generated-script" },',
|
|
817
|
+
" },",
|
|
818
|
+
" spec: {",
|
|
819
|
+
" contentHash,",
|
|
820
|
+
' mimeType: "text/javascript",',
|
|
821
|
+
' producer: { trust: "restricted" },',
|
|
822
|
+
' trust: "restricted",',
|
|
823
|
+
" },",
|
|
824
|
+
" }, {",
|
|
825
|
+
' fieldManager: "agent-agent-script-example",',
|
|
826
|
+
" idempotencyKey: `${ctx.input.conversationId}:artifact`,",
|
|
827
|
+
" });",
|
|
828
|
+
"",
|
|
829
|
+
" const observed = await nextEvent;",
|
|
830
|
+
' if (observed.done || observed.value.type !== "ADDED") {',
|
|
831
|
+
' throw new Error("artifact watch ended before observing the created resource");',
|
|
832
|
+
" }",
|
|
833
|
+
"",
|
|
834
|
+
" const reference = {",
|
|
835
|
+
" apiVersion: artifact.apiVersion,",
|
|
836
|
+
" kind: artifact.kind,",
|
|
837
|
+
" name: artifact.metadata.name,",
|
|
838
|
+
" namespace: artifact.metadata.namespace,",
|
|
839
|
+
" uid: artifact.metadata.uid,",
|
|
840
|
+
" };",
|
|
841
|
+
" const fetched = await ctx.orchestration.get(reference, {",
|
|
842
|
+
" resourceVersion: artifact.metadata.resourceVersion,",
|
|
843
|
+
" });",
|
|
844
|
+
" const listed = await ctx.orchestration.list(query, {",
|
|
845
|
+
" resourceVersion: artifact.metadata.resourceVersion,",
|
|
846
|
+
' resourceVersionMatch: "not-older-than",',
|
|
847
|
+
" limit: 10,",
|
|
848
|
+
" });",
|
|
849
|
+
" if (!fetched || !listed.items.some((item) => item.metadata.uid === artifact.metadata.uid)) {",
|
|
850
|
+
' throw new Error("created artifact was not readable through the resource facade");',
|
|
851
|
+
" }",
|
|
852
|
+
"",
|
|
853
|
+
" await ctx.orchestration.delete(reference, {",
|
|
854
|
+
" idempotencyKey: `${ctx.input.conversationId}:artifact-delete`,",
|
|
855
|
+
" preconditions: {",
|
|
856
|
+
" uid: artifact.metadata.uid,",
|
|
857
|
+
" resourceVersion: artifact.metadata.resourceVersion,",
|
|
858
|
+
" },",
|
|
859
|
+
" });",
|
|
860
|
+
" ctx.finish(`verified artifact lifecycle ${artifact.metadata.name}@${observed.value.resourceVersion}`);",
|
|
861
|
+
" } finally {",
|
|
862
|
+
" abortController.abort();",
|
|
863
|
+
" await events.return?.();",
|
|
864
|
+
" }",
|
|
865
|
+
"}",
|
|
866
|
+
""
|
|
867
|
+
].join("\n"),
|
|
868
|
+
[AgentAgentLoopDeclarativeAgentRunScriptId]: [
|
|
869
|
+
"// @ts-check",
|
|
870
|
+
"",
|
|
871
|
+
"function resourceName(value) {",
|
|
872
|
+
' const normalized = value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");',
|
|
873
|
+
' return (normalized || "agent-run").slice(0, 48);',
|
|
874
|
+
"}",
|
|
875
|
+
"",
|
|
876
|
+
"/** @param {import('../../loopAPI/agent-agent-loop/loop.js').AgentAgentScriptContext} ctx */",
|
|
877
|
+
"export default async function run(ctx) {",
|
|
878
|
+
" if (!ctx.agentClient) {",
|
|
879
|
+
' throw new Error("declarative-agent-run requires the orchestration resource facade");',
|
|
880
|
+
" }",
|
|
881
|
+
"",
|
|
882
|
+
" const metadata = ctx.profile?.metadata ?? {};",
|
|
883
|
+
' const childProfileId = typeof metadata.childProfileId === "string"',
|
|
884
|
+
" ? metadata.childProfileId",
|
|
885
|
+
" : ctx.agents[0]?.profileId;",
|
|
886
|
+
" if (!childProfileId) {",
|
|
887
|
+
' throw new Error("declarative-agent-run requires metadata.childProfileId or one configured agent");',
|
|
888
|
+
" }",
|
|
889
|
+
"",
|
|
890
|
+
" const baseName = resourceName(`child-${ctx.input.conversationId}`);",
|
|
891
|
+
" const workloadName = `${baseName}-workload`;",
|
|
892
|
+
" const runName = `${baseName}-run`;",
|
|
893
|
+
" const workload = await ctx.agentClient.createWorkload({",
|
|
894
|
+
" name: workloadName,",
|
|
895
|
+
" profileId: childProfileId,",
|
|
896
|
+
" promptReference: `conversation:${ctx.input.conversationId}:input`,",
|
|
897
|
+
' trust: "restricted",',
|
|
898
|
+
" placement: {",
|
|
899
|
+
' nodeSelector: { "memeloop.io/worker-pool": "restricted" },',
|
|
900
|
+
" antiAffinity: [ctx.input.conversationId],",
|
|
901
|
+
" },",
|
|
902
|
+
" modelPolicy: {",
|
|
903
|
+
' modelClass: "local-model",',
|
|
904
|
+
" budget: { maxTokens: 8_192 },",
|
|
905
|
+
" },",
|
|
906
|
+
" toolPolicy: {",
|
|
907
|
+
' defaultAction: "deny",',
|
|
908
|
+
' allowedToolClasses: ["read-only"],',
|
|
909
|
+
" },",
|
|
910
|
+
" networkPolicy: {",
|
|
911
|
+
' networkClass: "restricted-egress",',
|
|
912
|
+
' egress: "restricted",',
|
|
913
|
+
" },",
|
|
914
|
+
" storagePolicy: {",
|
|
915
|
+
' storageClass: "ephemeral",',
|
|
916
|
+
" },",
|
|
917
|
+
' completionPolicy: "complete",',
|
|
918
|
+
" idempotencyKey: `${ctx.input.conversationId}:workload`,",
|
|
919
|
+
" });",
|
|
920
|
+
" const agentRun = await ctx.agentClient.createRun({",
|
|
921
|
+
" name: runName,",
|
|
922
|
+
" workloadName: workload.metadata.name,",
|
|
923
|
+
" workloadNamespace: workload.metadata.namespace,",
|
|
924
|
+
" promptReference: `conversation:${ctx.input.conversationId}:input`,",
|
|
925
|
+
" timeoutMs: 120_000,",
|
|
926
|
+
" idempotencyKey: `${ctx.input.conversationId}:run`,",
|
|
927
|
+
" });",
|
|
928
|
+
"",
|
|
929
|
+
" if (metadata.waitForCompletion === true) {",
|
|
930
|
+
" await ctx.agentClient.waitForRunCondition(",
|
|
931
|
+
" agentRun.metadata.name,",
|
|
932
|
+
' { type: "Completed", status: "True" },',
|
|
933
|
+
" { timeout: 5_000, interval: 100 },",
|
|
934
|
+
" );",
|
|
935
|
+
" }",
|
|
936
|
+
"",
|
|
937
|
+
" ctx.finish(`scheduled ${workload.metadata.name}/${agentRun.metadata.name}`);",
|
|
938
|
+
"}",
|
|
939
|
+
""
|
|
940
|
+
].join("\n"),
|
|
941
|
+
[AgentAgentLoopQualityGateScriptId]: [
|
|
942
|
+
"// @ts-check",
|
|
943
|
+
"",
|
|
944
|
+
"function positiveInteger(value, fallback) {",
|
|
945
|
+
" const number = Number(value);",
|
|
946
|
+
" return Number.isFinite(number) && number > 0 ? Math.floor(number) : fallback;",
|
|
947
|
+
"}",
|
|
948
|
+
"",
|
|
949
|
+
"function asEntries(value, fallback) {",
|
|
950
|
+
" return Array.isArray(value) && value.length > 0 ? value : fallback;",
|
|
951
|
+
"}",
|
|
952
|
+
"",
|
|
953
|
+
"function withConversationIds(ctx, entries, phase, iteration) {",
|
|
954
|
+
" return entries.map((entry, index) => {",
|
|
955
|
+
' const record = typeof entry === "string" ? { profile: entry } : entry;',
|
|
956
|
+
" return {",
|
|
957
|
+
" ...record,",
|
|
958
|
+
" conversationId:",
|
|
959
|
+
" record.conversationId ?? `${ctx.input.conversationId}:${phase}:${iteration}:${index}`,",
|
|
960
|
+
" };",
|
|
961
|
+
" });",
|
|
962
|
+
"}",
|
|
963
|
+
"",
|
|
964
|
+
"function resultText(ctx, result) {",
|
|
965
|
+
" return result.text || ctx.formatAgentResults(result, { includeFailureSection: true });",
|
|
966
|
+
"}",
|
|
967
|
+
"",
|
|
968
|
+
"function reviewText(ctx, result) {",
|
|
969
|
+
" return ctx.formatAgentResults(result, { includeFailureSection: true });",
|
|
970
|
+
"}",
|
|
971
|
+
"",
|
|
972
|
+
"function approved(result) {",
|
|
973
|
+
" return (",
|
|
974
|
+
" result.failures.length === 0 &&",
|
|
975
|
+
" result.results.length > 0 &&",
|
|
976
|
+
" result.results.every((item) => /^\\s*APPROVED\\b/imu.test(item.text))",
|
|
977
|
+
" );",
|
|
978
|
+
"}",
|
|
979
|
+
"",
|
|
980
|
+
"function feedbackBlock(ctx, history) {",
|
|
981
|
+
' if (history.length === 0) return "No prior review feedback.";',
|
|
982
|
+
" return history",
|
|
983
|
+
" .map((entry) =>",
|
|
984
|
+
" [",
|
|
985
|
+
" `Iteration ${entry.iteration}`,",
|
|
986
|
+
" `Attempt:\\n${resultText(ctx, entry.attempt)}`,",
|
|
987
|
+
" `Review:\\n${reviewText(ctx, entry.review)}`,",
|
|
988
|
+
' ].join("\\n\\n"),',
|
|
989
|
+
" )",
|
|
990
|
+
' .join("\\n\\n---\\n\\n");',
|
|
991
|
+
"}",
|
|
992
|
+
"",
|
|
993
|
+
"function workerPrompt(ctx, goal, iteration, previousAttempt, history) {",
|
|
994
|
+
" if (!previousAttempt) return goal;",
|
|
995
|
+
" return [",
|
|
996
|
+
' "Continue working on the original goal until the reviewer can approve it.",',
|
|
997
|
+
' "Do not summarize the review. Produce the corrected deliverable itself.",',
|
|
998
|
+
" `Original goal:\\n${goal}`,",
|
|
999
|
+
" `Previous deliverable:\\n${resultText(ctx, previousAttempt)}`,",
|
|
1000
|
+
" `Review history:\\n${feedbackBlock(ctx, history)}`,",
|
|
1001
|
+
" `This is revision attempt ${iteration}.`,",
|
|
1002
|
+
' ].join("\\n\\n");',
|
|
1003
|
+
"}",
|
|
1004
|
+
"",
|
|
1005
|
+
"function reviewPrompt(ctx, goal, attempt, history) {",
|
|
1006
|
+
" return [",
|
|
1007
|
+
' "You are the quality gate for this delegated agent run.",',
|
|
1008
|
+
' "Return APPROVED on the first line only when the deliverable fully satisfies the original goal and is ready to send to the user.",',
|
|
1009
|
+
' "Return REVISE on the first line when more work is required, followed by concrete blocking issues and exact changes needed.",',
|
|
1010
|
+
' "Do not approve partial progress.",',
|
|
1011
|
+
" `Original goal:\\n${goal}`,",
|
|
1012
|
+
" `Candidate deliverable:\\n${resultText(ctx, attempt)}`,",
|
|
1013
|
+
" `Earlier review history:\\n${feedbackBlock(ctx, history)}`,",
|
|
1014
|
+
' ].join("\\n\\n");',
|
|
1015
|
+
"}",
|
|
1016
|
+
"",
|
|
1017
|
+
"async function runBatch(ctx, mode, input) {",
|
|
1018
|
+
' return mode === "sequential" ? ctx.runSequential(input) : ctx.runParallel(input);',
|
|
1019
|
+
"}",
|
|
1020
|
+
"",
|
|
1021
|
+
"/** @param {import('../../loopAPI/agent-agent-loop/loop.js').AgentAgentScriptContext} ctx */",
|
|
1022
|
+
"export default async function run(ctx) {",
|
|
1023
|
+
" const metadata = ctx.profile?.metadata ?? {};",
|
|
1024
|
+
" const goal = ctx.input.message;",
|
|
1025
|
+
" const maxIterations = positiveInteger(metadata.maxIterations, 4);",
|
|
1026
|
+
' const mode = metadata.mode === "sequential" ? "sequential" : "parallel";',
|
|
1027
|
+
' const reviewMode = metadata.reviewMode === "sequential" ? "sequential" : "parallel";',
|
|
1028
|
+
' const defaultAgents = ctx.getAgentEntries("agents");',
|
|
1029
|
+
" const workers = asEntries(",
|
|
1030
|
+
' ctx.getAgentEntries("workers"),',
|
|
1031
|
+
' asEntries(ctx.getAgentEntries("draftAgents"), defaultAgents),',
|
|
1032
|
+
" );",
|
|
1033
|
+
" const reviewers = asEntries(",
|
|
1034
|
+
' ctx.getAgentEntries("reviewers"),',
|
|
1035
|
+
' asEntries(ctx.getAgentEntries("reviewAgents"), defaultAgents),',
|
|
1036
|
+
" );",
|
|
1037
|
+
" const fixers = asEntries(",
|
|
1038
|
+
' ctx.getAgentEntries("fixers"),',
|
|
1039
|
+
' asEntries(ctx.getAgentEntries("revisionAgents"), workers),',
|
|
1040
|
+
" );",
|
|
1041
|
+
" const history = [];",
|
|
1042
|
+
" let attempt;",
|
|
1043
|
+
"",
|
|
1044
|
+
" if (workers.length === 0 || reviewers.length === 0) {",
|
|
1045
|
+
" ctx.finish(",
|
|
1046
|
+
' "AgentAgent quality gate requires worker and reviewer agents. Configure metadata.workers/reviewers or metadata.agents.",',
|
|
1047
|
+
" );",
|
|
1048
|
+
" return;",
|
|
1049
|
+
" }",
|
|
1050
|
+
"",
|
|
1051
|
+
" for (let iteration = 1; iteration <= maxIterations; iteration += 1) {",
|
|
1052
|
+
" if (ctx.isCancelled()) break;",
|
|
1053
|
+
" const activeWorkers = iteration === 1 ? workers : fixers;",
|
|
1054
|
+
" const attemptKey = `quality-gate:${iteration}:attempt`;",
|
|
1055
|
+
" const previousAttempt = attempt;",
|
|
1056
|
+
" const savedAttempt = await ctx.loadCheckpoint(attemptKey);",
|
|
1057
|
+
" if (savedAttempt) {",
|
|
1058
|
+
" attempt = savedAttempt;",
|
|
1059
|
+
" } else {",
|
|
1060
|
+
" ctx.emit({",
|
|
1061
|
+
' type: "thinking",',
|
|
1062
|
+
' data: { status: "quality-gate-work", conversationId: ctx.input.conversationId, iteration },',
|
|
1063
|
+
" });",
|
|
1064
|
+
" attempt = await runBatch(ctx, mode, {",
|
|
1065
|
+
' agents: withConversationIds(ctx, activeWorkers, "work", iteration),',
|
|
1066
|
+
" prompt: workerPrompt(ctx, goal, iteration, previousAttempt, history),",
|
|
1067
|
+
" });",
|
|
1068
|
+
" await ctx.checkpoint(attemptKey, attempt);",
|
|
1069
|
+
" }",
|
|
1070
|
+
"",
|
|
1071
|
+
" if (attempt.failures.length > 0 && attempt.results.length === 0) {",
|
|
1072
|
+
" history.push({",
|
|
1073
|
+
" iteration,",
|
|
1074
|
+
" attempt,",
|
|
1075
|
+
' review: { results: [], failures: attempt.failures, text: "" },',
|
|
1076
|
+
" });",
|
|
1077
|
+
" continue;",
|
|
1078
|
+
" }",
|
|
1079
|
+
"",
|
|
1080
|
+
" const reviewKey = `quality-gate:${iteration}:review`;",
|
|
1081
|
+
" let review = await ctx.loadCheckpoint(reviewKey);",
|
|
1082
|
+
" if (!review) {",
|
|
1083
|
+
" ctx.emit({",
|
|
1084
|
+
' type: "thinking",',
|
|
1085
|
+
" data: {",
|
|
1086
|
+
' status: "quality-gate-review",',
|
|
1087
|
+
" conversationId: ctx.input.conversationId,",
|
|
1088
|
+
" iteration,",
|
|
1089
|
+
" },",
|
|
1090
|
+
" });",
|
|
1091
|
+
" review = await runBatch(ctx, reviewMode, {",
|
|
1092
|
+
' agents: withConversationIds(ctx, reviewers, "review", iteration),',
|
|
1093
|
+
" prompt: reviewPrompt(ctx, goal, attempt, history),",
|
|
1094
|
+
" });",
|
|
1095
|
+
" await ctx.checkpoint(reviewKey, review);",
|
|
1096
|
+
" }",
|
|
1097
|
+
" history.push({ iteration, attempt, review });",
|
|
1098
|
+
"",
|
|
1099
|
+
" if (approved(review)) {",
|
|
1100
|
+
" ctx.finish(resultText(ctx, attempt));",
|
|
1101
|
+
" return;",
|
|
1102
|
+
" }",
|
|
1103
|
+
" }",
|
|
1104
|
+
"",
|
|
1105
|
+
" ctx.finish(",
|
|
1106
|
+
" [",
|
|
1107
|
+
' "Quality gate did not approve the delegated work before the iteration limit.",',
|
|
1108
|
+
' attempt ? resultText(ctx, attempt) : "No deliverable was produced.",',
|
|
1109
|
+
' "Review trail:",',
|
|
1110
|
+
" feedbackBlock(ctx, history),",
|
|
1111
|
+
" ]",
|
|
1112
|
+
" .filter(Boolean)",
|
|
1113
|
+
' .join("\\n\\n"),',
|
|
1114
|
+
" );",
|
|
1115
|
+
"}",
|
|
1116
|
+
""
|
|
1117
|
+
].join("\n")
|
|
1118
|
+
};
|
|
1119
|
+
function getBuiltinAgentAgentLoopSource(id) {
|
|
1120
|
+
return builtinAgentAgentLoopSources[id];
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// src/loopAPI/scriptLoader.ts
|
|
1124
|
+
var DEFAULT_POLICY = {
|
|
1125
|
+
allowBuiltin: true,
|
|
1126
|
+
allowFile: false,
|
|
1127
|
+
allowNetwork: false,
|
|
1128
|
+
allowSource: false,
|
|
1129
|
+
allowSpecifier: true
|
|
1130
|
+
};
|
|
1131
|
+
var LOADED_SCRIPT_METADATA = /* @__PURE__ */ Symbol("memeloop.loadedScriptMetadata");
|
|
1132
|
+
function isLoadedScriptFunction(value) {
|
|
1133
|
+
return typeof value === "function";
|
|
1134
|
+
}
|
|
1135
|
+
function getLoadedScriptMetadata(script) {
|
|
1136
|
+
if (!isLoadedScriptFunction(script)) return void 0;
|
|
1137
|
+
return script[LOADED_SCRIPT_METADATA];
|
|
1138
|
+
}
|
|
1139
|
+
function attachLoadedScriptMetadata(script, metadata) {
|
|
1140
|
+
if (getLoadedScriptMetadata(script) !== void 0) return;
|
|
1141
|
+
Object.defineProperty(script, LOADED_SCRIPT_METADATA, {
|
|
1142
|
+
value: metadata,
|
|
1143
|
+
enumerable: false,
|
|
1144
|
+
configurable: false,
|
|
1145
|
+
writable: false
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
var builtinScriptDigests = /* @__PURE__ */ new Set();
|
|
1149
|
+
function registerBuiltinScriptDigests(digests) {
|
|
1150
|
+
for (const digest of digests) {
|
|
1151
|
+
builtinScriptDigests.add(digest);
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
async function registerBuiltinScriptSources(sources) {
|
|
1155
|
+
const digests = [];
|
|
1156
|
+
for (const source of Object.values(sources)) {
|
|
1157
|
+
digests.push(await digestNormalizedScript(normalizeScript(source)));
|
|
1158
|
+
}
|
|
1159
|
+
registerBuiltinScriptDigests(digests);
|
|
1160
|
+
return digests;
|
|
1161
|
+
}
|
|
1162
|
+
function isRegisteredBuiltinScriptDigest(digest) {
|
|
1163
|
+
return builtinScriptDigests.has(digest);
|
|
1164
|
+
}
|
|
1165
|
+
var ScriptLoadDeniedError = class extends Error {
|
|
1166
|
+
constructor(digest, gateReason) {
|
|
1167
|
+
super(`Agent loop script load denied (sha256:${digest}): ${gateReason}`);
|
|
1168
|
+
this.digest = digest;
|
|
1169
|
+
this.gateReason = gateReason;
|
|
1170
|
+
this.name = "ScriptLoadDeniedError";
|
|
1171
|
+
}
|
|
1172
|
+
code = "SCRIPT_LOAD_DENIED";
|
|
1173
|
+
};
|
|
1174
|
+
var FAIL_CLOSED_SCRIPT_LOAD_GATE = {
|
|
1175
|
+
admitScriptLoad: () => ({
|
|
1176
|
+
allowed: false,
|
|
1177
|
+
reason: "No script load gate configured; non-builtin script sources are denied by default (fail-closed)"
|
|
1178
|
+
})
|
|
1179
|
+
};
|
|
1180
|
+
function getExportedScript(moduleExports) {
|
|
1181
|
+
if (typeof moduleExports === "function") return moduleExports;
|
|
1182
|
+
if (!moduleExports || typeof moduleExports !== "object") return void 0;
|
|
1183
|
+
const record = moduleExports;
|
|
1184
|
+
return record.default ?? record.run;
|
|
1185
|
+
}
|
|
1186
|
+
function sourceToDataSpecifier(source, name = "agent-loop-script.mjs") {
|
|
1187
|
+
return `data:text/javascript;charset=utf-8,${encodeURIComponent(`${source}
|
|
1188
|
+
//# sourceURL=${name}`)}`;
|
|
1189
|
+
}
|
|
1190
|
+
function normalizeScriptReference(scriptReference) {
|
|
1191
|
+
if (typeof scriptReference !== "string") return scriptReference;
|
|
1192
|
+
if (scriptReference.startsWith("builtin:")) return { kind: "builtin", id: scriptReference };
|
|
1193
|
+
return { kind: "specifier", specifier: scriptReference };
|
|
1194
|
+
}
|
|
1195
|
+
function isFileSpecifier(specifier) {
|
|
1196
|
+
return specifier.startsWith("file:") || specifier.startsWith("/") || specifier.startsWith("./") || specifier.startsWith("../");
|
|
1197
|
+
}
|
|
1198
|
+
function isNetworkSpecifier(specifier) {
|
|
1199
|
+
return specifier.startsWith("http:") || specifier.startsWith("https:");
|
|
1200
|
+
}
|
|
1201
|
+
function isSourceSpecifier(specifier) {
|
|
1202
|
+
return specifier.startsWith("data:text/javascript") || specifier.startsWith("data:application/javascript");
|
|
1203
|
+
}
|
|
1204
|
+
function decodeDataScriptSpecifier(specifier) {
|
|
1205
|
+
const commaIndex = specifier.indexOf(",");
|
|
1206
|
+
if (commaIndex < 0) return void 0;
|
|
1207
|
+
const metadata = specifier.slice("data:".length, commaIndex);
|
|
1208
|
+
const payload = specifier.slice(commaIndex + 1);
|
|
1209
|
+
try {
|
|
1210
|
+
if (metadata.split(";").includes("base64")) {
|
|
1211
|
+
return atob(payload);
|
|
1212
|
+
}
|
|
1213
|
+
return decodeURIComponent(payload);
|
|
1214
|
+
} catch {
|
|
1215
|
+
return void 0;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
function assertSpecifierAllowed(specifier, policy) {
|
|
1219
|
+
if (!policy.allowSpecifier) {
|
|
1220
|
+
throw new Error("Agent loop script import specifiers are disabled by policy.");
|
|
1221
|
+
}
|
|
1222
|
+
if (isSourceSpecifier(specifier) && !policy.allowSource) {
|
|
1223
|
+
throw new Error("Agent loop script source/data URLs are disabled by policy.");
|
|
1224
|
+
}
|
|
1225
|
+
if (isFileSpecifier(specifier) && !policy.allowFile) {
|
|
1226
|
+
throw new Error("Agent loop script file imports are disabled by policy.");
|
|
1227
|
+
}
|
|
1228
|
+
if (isNetworkSpecifier(specifier) && !policy.allowNetwork) {
|
|
1229
|
+
throw new Error("Agent loop script network imports are disabled by policy.");
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
async function loadAgentLoopScript(scriptReference, options = {}) {
|
|
1233
|
+
const policy = { ...DEFAULT_POLICY, ...options };
|
|
1234
|
+
const importModule = options.importModule ?? ((specifier) => import(specifier));
|
|
1235
|
+
const normalized = normalizeScriptReference(scriptReference);
|
|
1236
|
+
const scriptType = options.scriptType ?? "Agent loop script";
|
|
1237
|
+
let scriptSpecifier;
|
|
1238
|
+
let sourceForAdmission;
|
|
1239
|
+
if (normalized.kind === "builtin") {
|
|
1240
|
+
if (!policy.allowBuiltin) {
|
|
1241
|
+
throw new Error("Built-in agent loop scripts are disabled by policy.");
|
|
1242
|
+
}
|
|
1243
|
+
const source = options.getBuiltinScriptSource?.(normalized.id);
|
|
1244
|
+
if (!source) throw new Error(`Unknown built-in agent loop script: ${normalized.id}`);
|
|
1245
|
+
sourceForAdmission = source;
|
|
1246
|
+
scriptSpecifier = sourceToDataSpecifier(source, normalized.id);
|
|
1247
|
+
} else if (normalized.kind === "source") {
|
|
1248
|
+
if (!policy.allowSource) {
|
|
1249
|
+
throw new Error("Agent loop script source strings are disabled by policy.");
|
|
1250
|
+
}
|
|
1251
|
+
sourceForAdmission = normalized.source;
|
|
1252
|
+
scriptSpecifier = sourceToDataSpecifier(normalized.source, normalized.name);
|
|
1253
|
+
} else {
|
|
1254
|
+
scriptSpecifier = normalized.specifier;
|
|
1255
|
+
assertSpecifierAllowed(scriptSpecifier, policy);
|
|
1256
|
+
if (isSourceSpecifier(scriptSpecifier)) {
|
|
1257
|
+
sourceForAdmission = decodeDataScriptSpecifier(scriptSpecifier);
|
|
1258
|
+
if (sourceForAdmission === void 0) {
|
|
1259
|
+
throw new ScriptLoadDeniedError("undecodable", "data: script specifier payload could not be decoded");
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
let metadata;
|
|
1264
|
+
if (sourceForAdmission !== void 0) {
|
|
1265
|
+
const normalizedSource = normalizeScript(sourceForAdmission);
|
|
1266
|
+
const digest = await digestNormalizedScript(normalizedSource);
|
|
1267
|
+
if (isRegisteredBuiltinScriptDigest(digest)) {
|
|
1268
|
+
metadata = { digest, builtin: true, trustClass: "trusted" };
|
|
1269
|
+
} else {
|
|
1270
|
+
const gate = options.scriptLoadGate ?? FAIL_CLOSED_SCRIPT_LOAD_GATE;
|
|
1271
|
+
const decision = await gate.admitScriptLoad({ normalizedSource, digest, reference: normalized, scriptType });
|
|
1272
|
+
if (!decision.allowed) {
|
|
1273
|
+
throw new ScriptLoadDeniedError(digest, decision.reason ?? "denied by script load gate");
|
|
1274
|
+
}
|
|
1275
|
+
metadata = {
|
|
1276
|
+
digest,
|
|
1277
|
+
builtin: false,
|
|
1278
|
+
trustClass: decision.trustClass,
|
|
1279
|
+
runtimeClass: decision.runtimeClass,
|
|
1280
|
+
checkpointCompatible: decision.checkpointCompatible
|
|
1281
|
+
};
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const moduleExports = await importModule(scriptSpecifier);
|
|
1285
|
+
const exportedScript = getExportedScript(moduleExports);
|
|
1286
|
+
if (!isLoadedScriptFunction(exportedScript)) {
|
|
1287
|
+
throw new TypeError(
|
|
1288
|
+
`${scriptType} "${scriptSpecifier}" must export a default function or named run function.`
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
if (metadata) {
|
|
1292
|
+
attachLoadedScriptMetadata(exportedScript, metadata);
|
|
1293
|
+
}
|
|
1294
|
+
return exportedScript;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// src/loopAPI/agent-agent-loop/scriptLoader.ts
|
|
1298
|
+
var builtinDigestsRegistered;
|
|
1299
|
+
function ensureBuiltinDigestsRegistered() {
|
|
1300
|
+
builtinDigestsRegistered ??= registerBuiltinScriptSources(builtinAgentAgentLoopSources);
|
|
1301
|
+
return builtinDigestsRegistered;
|
|
1302
|
+
}
|
|
1303
|
+
async function loadAgentAgentLoopScript(scriptReference, options = {}) {
|
|
1304
|
+
await ensureBuiltinDigestsRegistered();
|
|
1305
|
+
return loadAgentLoopScript(scriptReference, {
|
|
1306
|
+
...options,
|
|
1307
|
+
getBuiltinScriptSource: getBuiltinAgentAgentLoopSource,
|
|
1308
|
+
scriptType: "AgentAgentLoop script"
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// src/loopAPI/agent-agent-loop/loop.ts
|
|
1313
|
+
var LOOP_ID = "agent-agent-loop";
|
|
1314
|
+
var LOOP_NAME = "AgentAgent Loop";
|
|
1315
|
+
var LOOP_DESC = "Orchestrates child agents to collaborate on a task. Supports sequential chaining, parallel execution, and feedback loops.";
|
|
1316
|
+
function isAsyncIterable(value) {
|
|
1317
|
+
return Boolean(value && typeof value === "object" && Symbol.asyncIterator in value);
|
|
1318
|
+
}
|
|
1319
|
+
function messageStep(message) {
|
|
1320
|
+
return { type: "message", data: message };
|
|
1321
|
+
}
|
|
1322
|
+
function stepText(step) {
|
|
1323
|
+
if (step.type !== "message") return void 0;
|
|
1324
|
+
if (typeof step.data === "string") return step.data;
|
|
1325
|
+
if (step.data && typeof step.data === "object" && "content" in step.data) {
|
|
1326
|
+
const content = step.data.content;
|
|
1327
|
+
return typeof content === "string" ? content : void 0;
|
|
1328
|
+
}
|
|
1329
|
+
return void 0;
|
|
1330
|
+
}
|
|
1331
|
+
function profileIdFromEntry(entry) {
|
|
1332
|
+
if (typeof entry === "string") return entry;
|
|
1333
|
+
return entry.profileId ?? entry.profile;
|
|
1334
|
+
}
|
|
1335
|
+
function readProfileAgentEntries(profile, key = "agents") {
|
|
1336
|
+
const metadata = profile?.metadata;
|
|
1337
|
+
if (!metadata) return void 0;
|
|
1338
|
+
const entries = metadata[key];
|
|
1339
|
+
if (Array.isArray(entries)) return entries;
|
|
1340
|
+
return void 0;
|
|
1341
|
+
}
|
|
1342
|
+
function normalizeAgentAgents(input, context, entries, prompt) {
|
|
1343
|
+
const configuredEntries = entries ?? context.agents ?? readProfileAgentEntries(context.profile) ?? [];
|
|
1344
|
+
return configuredEntries.flatMap((entry, index) => {
|
|
1345
|
+
const profileId = profileIdFromEntry(entry);
|
|
1346
|
+
if (!profileId) return [];
|
|
1347
|
+
const record = typeof entry === "string" ? {} : entry;
|
|
1348
|
+
return {
|
|
1349
|
+
...record,
|
|
1350
|
+
profileId,
|
|
1351
|
+
prompt: prompt ?? record.prompt,
|
|
1352
|
+
conversationId: record.conversationId ?? `${input.conversationId}:child:${index}`,
|
|
1353
|
+
label: record.label
|
|
1354
|
+
};
|
|
1355
|
+
});
|
|
1356
|
+
}
|
|
1357
|
+
function formatAgentResults(result, options = {}) {
|
|
1358
|
+
const emptyMessage = options.emptyMessage ?? "No child agent output.";
|
|
1359
|
+
const failureHeader = options.failureHeader ?? "Failed child agents:";
|
|
1360
|
+
const includeFailureSection = options.includeFailureSection !== false;
|
|
1361
|
+
const sections = [result.text || emptyMessage];
|
|
1362
|
+
if (includeFailureSection && result.failures.length > 0) {
|
|
1363
|
+
sections.push(`${failureHeader}
|
|
1364
|
+
${result.failures.map((failure) => `${failure.profileId}: ${failure.error}`).join("\n")}`);
|
|
1365
|
+
}
|
|
1366
|
+
return sections.filter(Boolean).join("\n\n");
|
|
1367
|
+
}
|
|
1368
|
+
function createScriptArguments(input, context, emittedSteps) {
|
|
1369
|
+
const agentEntries = context.agents ?? readProfileAgentEntries(context.profile) ?? [];
|
|
1370
|
+
const agents = normalizeAgentAgents(input, context, agentEntries);
|
|
1371
|
+
const getAgentEntries = (key = "agents") => {
|
|
1372
|
+
if (key === "agents") return agentEntries;
|
|
1373
|
+
return readProfileAgentEntries(context.profile, key) ?? [];
|
|
1374
|
+
};
|
|
1375
|
+
const emit = (step) => {
|
|
1376
|
+
emittedSteps.push(step);
|
|
1377
|
+
context.runtime?.emit?.(step);
|
|
1378
|
+
};
|
|
1379
|
+
const log = (event, data) => {
|
|
1380
|
+
context.runtime?.log?.(event, data);
|
|
1381
|
+
};
|
|
1382
|
+
const isCancelled = () => context.runtime?.signal?.cancelled === true;
|
|
1383
|
+
let childCounter = 0;
|
|
1384
|
+
const runAgent = async (childInput) => {
|
|
1385
|
+
if (isCancelled()) throw new Error("AgentAgent_Loop cancelled before child agent start");
|
|
1386
|
+
const profileId = childInput.profileId ?? childInput.profile;
|
|
1387
|
+
if (!profileId) throw new Error("ctx.runAgent requires profileId or profile");
|
|
1388
|
+
if (!context.runtime?.runChildAgent) throw new Error("ctx.runAgent requires runtime.runChildAgent");
|
|
1389
|
+
const childConversationId = childInput.conversationId ?? `${input.conversationId}:child:${profileId}:${++childCounter}`;
|
|
1390
|
+
const prompt = childInput.prompt ?? input.message;
|
|
1391
|
+
emit({
|
|
1392
|
+
type: "thinking",
|
|
1393
|
+
data: { status: "child-agent-started", profileId, conversationId: childConversationId }
|
|
1394
|
+
});
|
|
1395
|
+
const steps = [];
|
|
1396
|
+
const chunks = [];
|
|
1397
|
+
try {
|
|
1398
|
+
for await (const step of context.runtime.runChildAgent({
|
|
1399
|
+
profileId,
|
|
1400
|
+
prompt,
|
|
1401
|
+
conversationId: childConversationId
|
|
1402
|
+
})) {
|
|
1403
|
+
if (isCancelled()) throw new Error("AgentAgent_Loop cancelled during child agent run");
|
|
1404
|
+
steps.push(step);
|
|
1405
|
+
const text = stepText(step);
|
|
1406
|
+
if (text) chunks.push(text);
|
|
1407
|
+
emit({
|
|
1408
|
+
type: "thinking",
|
|
1409
|
+
data: { status: "child-agent-step", profileId, conversationId: childConversationId, step }
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1414
|
+
emit({
|
|
1415
|
+
type: "thinking",
|
|
1416
|
+
data: { status: "child-agent-failed", profileId, conversationId: childConversationId, error: message }
|
|
1417
|
+
});
|
|
1418
|
+
throw error;
|
|
1419
|
+
}
|
|
1420
|
+
emit({
|
|
1421
|
+
type: "thinking",
|
|
1422
|
+
data: { status: "child-agent-completed", profileId, conversationId: childConversationId }
|
|
1423
|
+
});
|
|
1424
|
+
return { profileId, conversationId: childConversationId, steps, text: chunks.join("").trim() };
|
|
1425
|
+
};
|
|
1426
|
+
const runBatch = async (batchInput, mode) => {
|
|
1427
|
+
const batchAgents = normalizeAgentAgents(input, context, batchInput?.agents, batchInput?.prompt);
|
|
1428
|
+
const continueOnError = batchInput?.continueOnError !== false;
|
|
1429
|
+
const results = [];
|
|
1430
|
+
const failures = [];
|
|
1431
|
+
const runOne = async (agent) => {
|
|
1432
|
+
if (isCancelled()) {
|
|
1433
|
+
emit({
|
|
1434
|
+
type: "thinking",
|
|
1435
|
+
data: { status: "cancelled", conversationId: input.conversationId }
|
|
1436
|
+
});
|
|
1437
|
+
return;
|
|
1438
|
+
}
|
|
1439
|
+
try {
|
|
1440
|
+
const result = await runAgent(agent);
|
|
1441
|
+
results.push(result);
|
|
1442
|
+
} catch (error) {
|
|
1443
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1444
|
+
failures.push({ profileId: agent.profileId, conversationId: agent.conversationId, error: message });
|
|
1445
|
+
if (!continueOnError) throw error;
|
|
1446
|
+
}
|
|
1447
|
+
};
|
|
1448
|
+
if (mode === "parallel") {
|
|
1449
|
+
await Promise.all(batchAgents.map((agent) => runOne(agent)));
|
|
1450
|
+
} else {
|
|
1451
|
+
for (const agent of batchAgents) {
|
|
1452
|
+
await runOne(agent);
|
|
1453
|
+
if (isCancelled()) break;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
return { results, failures, text: results.map((result) => result.text).filter(Boolean).join("\n\n") };
|
|
1457
|
+
};
|
|
1458
|
+
const agentClient = context.runtime?.orchestration ? createAgentClient(context.runtime.orchestration) : void 0;
|
|
1459
|
+
const scriptClient = context.runtime?.scriptDeployment ? createScriptDeploymentClient(context.runtime.scriptDeployment) : void 0;
|
|
1460
|
+
return {
|
|
1461
|
+
input,
|
|
1462
|
+
context,
|
|
1463
|
+
profile: context.profile,
|
|
1464
|
+
agents,
|
|
1465
|
+
getAgentEntries,
|
|
1466
|
+
runtime: context.runtime,
|
|
1467
|
+
orchestration: context.runtime?.orchestration,
|
|
1468
|
+
agentClient,
|
|
1469
|
+
scriptClient,
|
|
1470
|
+
runAgent,
|
|
1471
|
+
runAgents: (inputs) => Promise.all(inputs.map(runAgent)),
|
|
1472
|
+
runSequential: (batchInput) => runBatch(batchInput, "sequential"),
|
|
1473
|
+
runParallel: (batchInput) => runBatch(batchInput, "parallel"),
|
|
1474
|
+
formatAgentResults,
|
|
1475
|
+
finishAgentResults: (result, options) => {
|
|
1476
|
+
emit(messageStep(formatAgentResults(result, options)));
|
|
1477
|
+
},
|
|
1478
|
+
emit,
|
|
1479
|
+
finish: (message) => {
|
|
1480
|
+
emit(typeof message === "string" ? messageStep(message) : message);
|
|
1481
|
+
},
|
|
1482
|
+
isCancelled,
|
|
1483
|
+
log,
|
|
1484
|
+
state: context.runtime?.state ?? {
|
|
1485
|
+
get: async () => void 0,
|
|
1486
|
+
set: async () => void 0,
|
|
1487
|
+
update: async () => void 0
|
|
1488
|
+
},
|
|
1489
|
+
checkpoint: context.runtime?.checkpoint ?? (async () => void 0),
|
|
1490
|
+
loadCheckpoint: context.runtime?.loadCheckpoint ?? (async () => void 0)
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
async function* drainEmittedSteps(steps) {
|
|
1494
|
+
while (steps.length > 0) {
|
|
1495
|
+
const step = steps.shift();
|
|
1496
|
+
if (step) yield step;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
async function* runScript(script, input, context) {
|
|
1500
|
+
const emittedSteps = [];
|
|
1501
|
+
const scriptArguments = createScriptArguments(input, context, emittedSteps);
|
|
1502
|
+
const result = await script(scriptArguments);
|
|
1503
|
+
yield* drainEmittedSteps(emittedSteps);
|
|
1504
|
+
if (isAsyncIterable(result)) {
|
|
1505
|
+
yield* result;
|
|
1506
|
+
yield* drainEmittedSteps(emittedSteps);
|
|
1507
|
+
} else if (typeof result === "string") {
|
|
1508
|
+
yield messageStep(result);
|
|
1509
|
+
} else if (Array.isArray(result)) {
|
|
1510
|
+
yield* result;
|
|
1511
|
+
} else if (result) {
|
|
1512
|
+
yield result;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
function asAgentAgentContext(context) {
|
|
1516
|
+
return context;
|
|
1517
|
+
}
|
|
1518
|
+
async function resolveScript(context) {
|
|
1519
|
+
if (context.script) return context.script;
|
|
1520
|
+
const scriptReference = context.profile?.scriptReference ?? context.profile?.scriptRef ?? context.profile?.script;
|
|
1521
|
+
if (scriptReference) {
|
|
1522
|
+
if (context.loadScript) return context.loadScript(scriptReference, context);
|
|
1523
|
+
return loadAgentAgentLoopScript(scriptReference, context.scriptPolicy);
|
|
1524
|
+
}
|
|
1525
|
+
return void 0;
|
|
1526
|
+
}
|
|
1527
|
+
function createAgentAgentLoopDefinition() {
|
|
1528
|
+
return {
|
|
1529
|
+
id: LOOP_ID,
|
|
1530
|
+
name: LOOP_NAME,
|
|
1531
|
+
description: LOOP_DESC,
|
|
1532
|
+
createRunner: (rawContext) => {
|
|
1533
|
+
return async function* agentAgentLoop(input) {
|
|
1534
|
+
const context = asAgentAgentContext(rawContext);
|
|
1535
|
+
const script = await resolveScript(context);
|
|
1536
|
+
yield {
|
|
1537
|
+
type: "thinking",
|
|
1538
|
+
data: { status: "agent-agent-loop-loop-started", conversationId: input.conversationId }
|
|
1539
|
+
};
|
|
1540
|
+
context.runtime?.log?.("agent-agent-loop-loop-started", {
|
|
1541
|
+
conversationId: input.conversationId,
|
|
1542
|
+
profileId: context.profile?.id
|
|
1543
|
+
});
|
|
1544
|
+
if (script) {
|
|
1545
|
+
yield* runScript(script, input, context);
|
|
1546
|
+
yield {
|
|
1547
|
+
type: "thinking",
|
|
1548
|
+
data: { status: "completed", conversationId: input.conversationId }
|
|
1549
|
+
};
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
yield {
|
|
1553
|
+
type: "thinking",
|
|
1554
|
+
data: { status: "script-missing", conversationId: input.conversationId }
|
|
1555
|
+
};
|
|
1556
|
+
yield {
|
|
1557
|
+
type: "message",
|
|
1558
|
+
data: "AgentAgentLoop requires an explicit loop script. Configure profile.scriptReference or provide context.script."
|
|
1559
|
+
};
|
|
1560
|
+
yield {
|
|
1561
|
+
type: "thinking",
|
|
1562
|
+
data: { status: "completed", conversationId: input.conversationId }
|
|
1563
|
+
};
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1567
|
+
}
|
|
1568
|
+
function getAgentAgentLoopId() {
|
|
1569
|
+
return LOOP_ID;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/loops/agent-tool-loop/builtinLoopSources.ts
|
|
1573
|
+
var AgentToolLoopDefaultScriptId = "builtin:agent-tool-loop/default";
|
|
1574
|
+
var BUILTIN_AGENT_TOOL_LOOP_DEFAULT_SCRIPT_ID = AgentToolLoopDefaultScriptId;
|
|
1575
|
+
var builtinAgentToolLoopSources = {
|
|
1576
|
+
[AgentToolLoopDefaultScriptId]: [
|
|
1577
|
+
"// @ts-check",
|
|
1578
|
+
"",
|
|
1579
|
+
"/** @param {import('../../loopAPI/agent-tool-loop/loop.js').AgentToolLoopScriptContext} ctx */",
|
|
1580
|
+
"export default async function* run(ctx) {",
|
|
1581
|
+
" const state = ctx.createState();",
|
|
1582
|
+
"",
|
|
1583
|
+
" try {",
|
|
1584
|
+
" const start = await ctx.startTurn(state);",
|
|
1585
|
+
" if (start.step) yield start.step;",
|
|
1586
|
+
" if (start.action === 'stop') return;",
|
|
1587
|
+
"",
|
|
1588
|
+
" while (true) {",
|
|
1589
|
+
" const result = yield* ctx.runIteration(state);",
|
|
1590
|
+
" if (result.action === 'stop') return;",
|
|
1591
|
+
" }",
|
|
1592
|
+
" } catch (error) {",
|
|
1593
|
+
" await ctx.stopTurn(state, 'error');",
|
|
1594
|
+
" throw error;",
|
|
1595
|
+
" } finally {",
|
|
1596
|
+
" await ctx.stopTurn(state);",
|
|
1597
|
+
" }",
|
|
1598
|
+
"}"
|
|
1599
|
+
].join("\n")
|
|
1600
|
+
};
|
|
1601
|
+
function getBuiltinAgentToolLoopSource(id) {
|
|
1602
|
+
return builtinAgentToolLoopSources[id];
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
// src/loopAPI/agent-tool-loop/scriptLoader.ts
|
|
1606
|
+
var builtinDigestsRegistered2;
|
|
1607
|
+
function ensureBuiltinDigestsRegistered2() {
|
|
1608
|
+
builtinDigestsRegistered2 ??= registerBuiltinScriptSources(builtinAgentToolLoopSources);
|
|
1609
|
+
return builtinDigestsRegistered2;
|
|
1610
|
+
}
|
|
1611
|
+
async function loadAgentToolLoopScript(scriptReference, options = {}) {
|
|
1612
|
+
await ensureBuiltinDigestsRegistered2();
|
|
1613
|
+
return loadAgentLoopScript(scriptReference, {
|
|
1614
|
+
...options,
|
|
1615
|
+
getBuiltinScriptSource: getBuiltinAgentToolLoopSource,
|
|
1616
|
+
scriptType: "AgentToolLoop script"
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
// src/loopAPI/agent-tool-loop/scriptRunner.ts
|
|
1621
|
+
function isAsyncIterable2(value) {
|
|
1622
|
+
return Boolean(value && typeof value === "object" && Symbol.asyncIterator in value);
|
|
1623
|
+
}
|
|
1624
|
+
function messageStep2(message) {
|
|
1625
|
+
return { type: "message", data: message };
|
|
1626
|
+
}
|
|
1627
|
+
async function* drainEmittedSteps2(steps) {
|
|
1628
|
+
while (steps.length > 0) {
|
|
1629
|
+
const step = steps.shift();
|
|
1630
|
+
if (step) yield step;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
function asAgentToolLoopContext(rawContext) {
|
|
1634
|
+
return rawContext;
|
|
1635
|
+
}
|
|
1636
|
+
async function resolveAgentToolLoopScript(context) {
|
|
1637
|
+
if (context.script) return context.script;
|
|
1638
|
+
const scriptReference = context.profile?.scriptReference ?? context.profile?.scriptRef ?? context.profile?.script;
|
|
1639
|
+
if (!scriptReference) return void 0;
|
|
1640
|
+
if (context.loadScript) return context.loadScript(scriptReference, context);
|
|
1641
|
+
return loadAgentToolLoopScript(scriptReference, context.scriptPolicy);
|
|
1642
|
+
}
|
|
1643
|
+
function createAgentToolLoopScriptContext(input, context, emittedSteps) {
|
|
1644
|
+
const emit = (step) => {
|
|
1645
|
+
emittedSteps.push(step);
|
|
1646
|
+
context.runtime?.emit?.(step);
|
|
1647
|
+
};
|
|
1648
|
+
return {
|
|
1649
|
+
input,
|
|
1650
|
+
context,
|
|
1651
|
+
profile: context.profile,
|
|
1652
|
+
createState: () => createAgentToolLoopState(context),
|
|
1653
|
+
startTurn: (state) => startAgentToolLoopTurn(context, input, state),
|
|
1654
|
+
runIteration: (state) => runAgentToolLoopIteration(context, input, state),
|
|
1655
|
+
stopTurn: (state, reason) => stopAgentToolLoopTurn(context, input, state, reason),
|
|
1656
|
+
emit,
|
|
1657
|
+
finish: (message) => {
|
|
1658
|
+
emit(typeof message === "string" ? messageStep2(message) : message);
|
|
1659
|
+
},
|
|
1660
|
+
isCancelled: () => context.runtime?.signal?.cancelled === true || context.agentToolLoop?.isCancelled?.(input.conversationId) === true,
|
|
1661
|
+
log: (event, data) => {
|
|
1662
|
+
context.runtime?.log?.(event, data);
|
|
1663
|
+
context.logger?.debug?.(event, data);
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
async function* runAgentToolLoopScript(script, input, context) {
|
|
1668
|
+
const emittedSteps = [];
|
|
1669
|
+
const result = await script(createAgentToolLoopScriptContext(input, context, emittedSteps));
|
|
1670
|
+
yield* drainEmittedSteps2(emittedSteps);
|
|
1671
|
+
if (isAsyncIterable2(result)) {
|
|
1672
|
+
yield* result;
|
|
1673
|
+
yield* drainEmittedSteps2(emittedSteps);
|
|
1674
|
+
} else if (typeof result === "string") {
|
|
1675
|
+
yield messageStep2(result);
|
|
1676
|
+
} else if (Array.isArray(result)) {
|
|
1677
|
+
yield* result;
|
|
1678
|
+
} else if (result) {
|
|
1679
|
+
yield result;
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
// src/loopAPI/agent-tool-loop/loop.ts
|
|
1684
|
+
function createAgentToolLoopDefinition(name = "AgentToolLoop") {
|
|
1685
|
+
return {
|
|
1686
|
+
id: "agent-tool-loop",
|
|
1687
|
+
name,
|
|
1688
|
+
description: "Agent/tool loop that alternates between LLM output and external tool execution.",
|
|
1689
|
+
createRunner: (rawContext) => {
|
|
1690
|
+
const context = asAgentToolLoopContext(rawContext);
|
|
1691
|
+
return async function* agentToolLoop(input) {
|
|
1692
|
+
const script = await resolveAgentToolLoopScript(context);
|
|
1693
|
+
if (script) {
|
|
1694
|
+
yield* runAgentToolLoopScript(script, input, context);
|
|
1695
|
+
return;
|
|
1696
|
+
}
|
|
1697
|
+
yield* createAgentToolLoopRunner(context)(input);
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
// src/loopAPI/plugins/builtinLoopsPlugin.ts
|
|
1704
|
+
var AGENT_TOOL_LOOP_ID = "agent-tool-loop";
|
|
1705
|
+
var AGENT_AGENT_LOOP_ID = getAgentAgentLoopId();
|
|
1706
|
+
function registerBuiltinLoops() {
|
|
1707
|
+
const registry = getLoopRegistry();
|
|
1708
|
+
if (!registry.getLoop(AGENT_TOOL_LOOP_ID)) {
|
|
1709
|
+
registry.registerLoop(createAgentToolLoopDefinition("AgentToolLoop"));
|
|
1710
|
+
}
|
|
1711
|
+
if (!registry.getLoop(AGENT_AGENT_LOOP_ID)) {
|
|
1712
|
+
registry.registerLoop(createAgentAgentLoopDefinition());
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
// src/tools/builtins/askQuestion.ts
|
|
1717
|
+
import { z } from "zod";
|
|
1718
|
+
|
|
1719
|
+
// src/tools/builtins/questionWaitRegistry.ts
|
|
1720
|
+
var pending = /* @__PURE__ */ new Map();
|
|
1721
|
+
function resolveQuestionAnswer(questionId, answer) {
|
|
1722
|
+
const p = pending.get(questionId);
|
|
1723
|
+
if (!p) return false;
|
|
1724
|
+
clearTimeout(p.timer);
|
|
1725
|
+
pending.delete(questionId);
|
|
1726
|
+
p.resolve(answer);
|
|
1727
|
+
return true;
|
|
1728
|
+
}
|
|
1729
|
+
function waitForQuestionAnswer(questionId, timeoutMs) {
|
|
1730
|
+
return new Promise((resolve, reject) => {
|
|
1731
|
+
const timer = setTimeout(() => {
|
|
1732
|
+
pending.delete(questionId);
|
|
1733
|
+
reject(new Error("askQuestion_timeout"));
|
|
1734
|
+
}, timeoutMs);
|
|
1735
|
+
pending.set(questionId, { resolve, reject, timer });
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// src/tools/builtins/askQuestion.ts
|
|
1740
|
+
var askQuestionConfigSchema = z.object({
|
|
1741
|
+
question: z.string().min(1),
|
|
1742
|
+
/**
|
|
1743
|
+
* Desktop / TidGi 的 LLM 工具参数里通常不会显式携带 conversationId,
|
|
1744
|
+
* 由宿主侧上下文负责关联;这里允许缺省,交给宿主回调侧做路由。
|
|
1745
|
+
*/
|
|
1746
|
+
conversationId: z.string().min(1).optional(),
|
|
1747
|
+
timeoutMs: z.number().int().positive().max(36e5).optional(),
|
|
1748
|
+
inputType: z.enum(["single-select", "multi-select", "text"]).optional(),
|
|
1749
|
+
options: z.array(
|
|
1750
|
+
z.object({
|
|
1751
|
+
label: z.string(),
|
|
1752
|
+
description: z.string().optional()
|
|
1753
|
+
})
|
|
1754
|
+
).optional(),
|
|
1755
|
+
allowFreeform: z.boolean().optional().default(true)
|
|
1756
|
+
});
|
|
1757
|
+
var ASK_QUESTION_TOOL_ID = "ask-question";
|
|
1758
|
+
async function askQuestionImpl(arguments_, context) {
|
|
1759
|
+
const parsed = askQuestionConfigSchema.safeParse(arguments_);
|
|
1760
|
+
if (!parsed.success) {
|
|
1761
|
+
return { error: "invalid_askQuestion_args" };
|
|
1762
|
+
}
|
|
1763
|
+
const { question, conversationId, timeoutMs, inputType, options, allowFreeform } = parsed.data;
|
|
1764
|
+
const questionId = crypto.randomUUID();
|
|
1765
|
+
const timeout = timeoutMs ?? 3e5;
|
|
1766
|
+
context.notifyAskQuestion?.({
|
|
1767
|
+
questionId,
|
|
1768
|
+
question,
|
|
1769
|
+
conversationId,
|
|
1770
|
+
inputType,
|
|
1771
|
+
options,
|
|
1772
|
+
allowFreeform
|
|
1773
|
+
});
|
|
1774
|
+
try {
|
|
1775
|
+
const answer = await waitForQuestionAnswer(questionId, timeout);
|
|
1776
|
+
return { result: answer };
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
return { error: error instanceof Error ? error.message : "askQuestion_failed" };
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// src/tools/builtins/askUserQuestion.ts
|
|
1783
|
+
import { z as z2 } from "zod";
|
|
1784
|
+
var askUserQuestionConfigSchema = z2.object({
|
|
1785
|
+
question: z2.string().min(1).describe("The question to ask the user"),
|
|
1786
|
+
inputType: z2.enum(["text", "single-select", "multi-select"]).optional().default("text").describe("Type of input expected: text, single-select, or multi-select"),
|
|
1787
|
+
options: z2.array(
|
|
1788
|
+
z2.object({
|
|
1789
|
+
label: z2.string().min(1),
|
|
1790
|
+
description: z2.string().optional()
|
|
1791
|
+
})
|
|
1792
|
+
).optional().describe("Options for single-select or multi-select input types"),
|
|
1793
|
+
allowFreeform: z2.boolean().optional().default(true).describe("Allow free-text input even for select types"),
|
|
1794
|
+
timeoutMs: z2.number().int().positive().max(36e5).optional().default(3e5).describe("Timeout in milliseconds (default 5 minutes)")
|
|
1795
|
+
});
|
|
1796
|
+
var ASK_USER_QUESTION_TOOL_ID = "askUserQuestion";
|
|
1797
|
+
async function askUserQuestionImpl(arguments_, context) {
|
|
1798
|
+
const parsed = askUserQuestionConfigSchema.safeParse(arguments_);
|
|
1799
|
+
if (!parsed.success) {
|
|
1800
|
+
return { error: `invalid_askUserQuestion_args: ${parsed.error.message}` };
|
|
1801
|
+
}
|
|
1802
|
+
const { question, inputType, options, allowFreeform, timeoutMs } = parsed.data;
|
|
1803
|
+
const questionId = crypto.randomUUID();
|
|
1804
|
+
const conversationId = context.agent?.id ?? context.activeToolConversationId;
|
|
1805
|
+
context.notifyAskQuestion?.({
|
|
1806
|
+
questionId,
|
|
1807
|
+
question,
|
|
1808
|
+
conversationId,
|
|
1809
|
+
inputType,
|
|
1810
|
+
options,
|
|
1811
|
+
allowFreeform
|
|
1812
|
+
});
|
|
1813
|
+
try {
|
|
1814
|
+
const answer = await waitForQuestionAnswer(questionId, timeoutMs);
|
|
1815
|
+
return { result: answer };
|
|
1816
|
+
} catch (error) {
|
|
1817
|
+
const message = error instanceof Error ? error.message : "askUserQuestion_failed";
|
|
1818
|
+
return { error: message };
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
// src/tools/builtins/mcpClient.ts
|
|
1823
|
+
var TOOL_ID = "mcpClient";
|
|
1824
|
+
var mcpClientConfigSchema = {
|
|
1825
|
+
type: "object",
|
|
1826
|
+
properties: {
|
|
1827
|
+
nodeId: { type: "string", description: "Target node ID" },
|
|
1828
|
+
serverName: { type: "string", description: "MCP server name on that node" },
|
|
1829
|
+
toolName: { type: "string", description: "Tool to invoke" },
|
|
1830
|
+
args: { type: "object", description: "Tool arguments" }
|
|
1831
|
+
},
|
|
1832
|
+
required: ["nodeId", "serverName", "toolName"]
|
|
1833
|
+
};
|
|
1834
|
+
var mcpClientImpl = async (arguments_, context) => {
|
|
1835
|
+
const nodeId = arguments_.nodeId;
|
|
1836
|
+
const serverName = arguments_.serverName;
|
|
1837
|
+
const toolName = arguments_.toolName;
|
|
1838
|
+
const toolArguments = arguments_.args ?? {};
|
|
1839
|
+
if (!nodeId || !serverName || !toolName) {
|
|
1840
|
+
return {
|
|
1841
|
+
error: "mcpClient requires nodeId, serverName, and toolName"
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
if (!context.mcpCallRemote) {
|
|
1845
|
+
return {
|
|
1846
|
+
error: "MCP proxy not configured (no mcpCallRemote in context). Connect to nodes that expose MCP."
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
try {
|
|
1850
|
+
const result = await context.mcpCallRemote(nodeId, serverName, toolName, toolArguments);
|
|
1851
|
+
return { result };
|
|
1852
|
+
} catch (error) {
|
|
1853
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1854
|
+
return { error: `MCP call failed: ${message}` };
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
function getMcpClientToolId() {
|
|
1858
|
+
return TOOL_ID;
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// src/tools/builtins/mcpForward.ts
|
|
1862
|
+
var TOOL_ID2 = "mcpForward";
|
|
1863
|
+
var mcpForwardConfigSchema = {
|
|
1864
|
+
type: "object",
|
|
1865
|
+
properties: {
|
|
1866
|
+
action: {
|
|
1867
|
+
type: "string",
|
|
1868
|
+
enum: ["list", "listTools"],
|
|
1869
|
+
description: "Action: 'list' returns nodes with MCP servers, 'listTools' returns all available MCP tools across nodes"
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
var mcpForwardImpl = async (arguments_, context) => {
|
|
1874
|
+
const action = arguments_.action ?? "list";
|
|
1875
|
+
if (!context.getPeers) {
|
|
1876
|
+
return { error: "Peer list not configured (no getPeers)." };
|
|
1877
|
+
}
|
|
1878
|
+
if (!context.sendRpcToNode) {
|
|
1879
|
+
return { error: "Remote node RPC not configured (no sendRpcToNode)." };
|
|
1880
|
+
}
|
|
1881
|
+
const peers = await context.getPeers();
|
|
1882
|
+
const online = peers.filter((p) => p.reachability.state === "online");
|
|
1883
|
+
if (action === "list") {
|
|
1884
|
+
const result = [];
|
|
1885
|
+
for (const node of online) {
|
|
1886
|
+
try {
|
|
1887
|
+
const response = await context.sendRpcToNode(
|
|
1888
|
+
node.peerId,
|
|
1889
|
+
"memeloop.mcp.listServers",
|
|
1890
|
+
{}
|
|
1891
|
+
);
|
|
1892
|
+
const servers = Array.isArray(response?.servers) ? response.servers : [];
|
|
1893
|
+
if (servers.length > 0) {
|
|
1894
|
+
result.push({
|
|
1895
|
+
nodeId: node.peerId,
|
|
1896
|
+
name: node.displayName,
|
|
1897
|
+
mcpServers: servers
|
|
1898
|
+
});
|
|
1899
|
+
}
|
|
1900
|
+
} catch {
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
return { nodes: result };
|
|
1904
|
+
}
|
|
1905
|
+
if (action === "listTools") {
|
|
1906
|
+
const allTools = [];
|
|
1907
|
+
for (const node of online) {
|
|
1908
|
+
try {
|
|
1909
|
+
const response = await context.sendRpcToNode(
|
|
1910
|
+
node.peerId,
|
|
1911
|
+
"memeloop.mcp.listTools",
|
|
1912
|
+
{}
|
|
1913
|
+
);
|
|
1914
|
+
const tools = Array.isArray(response?.tools) ? response.tools : [];
|
|
1915
|
+
for (const tool of tools) {
|
|
1916
|
+
allTools.push({
|
|
1917
|
+
nodeId: node.peerId,
|
|
1918
|
+
serverName: tool.serverName,
|
|
1919
|
+
name: tool.name,
|
|
1920
|
+
description: tool.description
|
|
1921
|
+
});
|
|
1922
|
+
}
|
|
1923
|
+
} catch {
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
return { tools: allTools };
|
|
1927
|
+
}
|
|
1928
|
+
return { error: `Unknown action: ${action}` };
|
|
1929
|
+
};
|
|
1930
|
+
function getMcpForwardToolId() {
|
|
1931
|
+
return TOOL_ID2;
|
|
1932
|
+
}
|
|
1933
|
+
|
|
1934
|
+
// src/tools/builtins/orchestration.ts
|
|
1935
|
+
var ORCHESTRATION_TOOL_ID = "orchestration";
|
|
1936
|
+
var orchestrationConfigSchema = {
|
|
1937
|
+
type: "object",
|
|
1938
|
+
properties: {
|
|
1939
|
+
action: {
|
|
1940
|
+
type: "string",
|
|
1941
|
+
enum: ["capabilities", "apply", "get", "list", "wait", "delete"],
|
|
1942
|
+
description: "Declarative orchestration resource operation."
|
|
1943
|
+
},
|
|
1944
|
+
resource: {
|
|
1945
|
+
type: "object",
|
|
1946
|
+
description: "Resource manifest for apply. status and actor fields are not accepted."
|
|
1947
|
+
},
|
|
1948
|
+
reference: {
|
|
1949
|
+
type: "object",
|
|
1950
|
+
description: "Resource reference for get, wait, or delete."
|
|
1951
|
+
},
|
|
1952
|
+
query: {
|
|
1953
|
+
type: "object",
|
|
1954
|
+
description: "Resource query for list."
|
|
1955
|
+
},
|
|
1956
|
+
condition: {
|
|
1957
|
+
type: "object",
|
|
1958
|
+
description: "Condition to wait for. Required when action is wait."
|
|
1959
|
+
},
|
|
1960
|
+
options: {
|
|
1961
|
+
type: "object",
|
|
1962
|
+
description: "Operation options. Only documented fields are forwarded."
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
required: ["action"]
|
|
1966
|
+
};
|
|
1967
|
+
function objectValue(value, field) {
|
|
1968
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1969
|
+
throw invalidError(`${field} must be an object`);
|
|
1970
|
+
}
|
|
1971
|
+
return value;
|
|
1972
|
+
}
|
|
1973
|
+
function invalidError(message) {
|
|
1974
|
+
return new OrchestrationError({ code: "INVALID", message, retryable: false });
|
|
1975
|
+
}
|
|
1976
|
+
function optionalString(value) {
|
|
1977
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1978
|
+
}
|
|
1979
|
+
function optionalBoolean(value) {
|
|
1980
|
+
return typeof value === "boolean" ? value : void 0;
|
|
1981
|
+
}
|
|
1982
|
+
function stringRecord(value) {
|
|
1983
|
+
if (value === void 0) return void 0;
|
|
1984
|
+
const record = objectValue(value, "record");
|
|
1985
|
+
const entries = Object.entries(record);
|
|
1986
|
+
if (entries.some(([, entry]) => typeof entry !== "string")) {
|
|
1987
|
+
throw invalidError("record values must be strings");
|
|
1988
|
+
}
|
|
1989
|
+
return Object.fromEntries(entries);
|
|
1990
|
+
}
|
|
1991
|
+
function metadataValue(value) {
|
|
1992
|
+
const metadata = objectValue(value, "resource.metadata");
|
|
1993
|
+
return {
|
|
1994
|
+
name: optionalString(metadata.name),
|
|
1995
|
+
generateName: optionalString(metadata.generateName),
|
|
1996
|
+
namespace: optionalString(metadata.namespace),
|
|
1997
|
+
labels: stringRecord(metadata.labels),
|
|
1998
|
+
annotations: stringRecord(metadata.annotations)
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
function resourceValue(value) {
|
|
2002
|
+
const resource = objectValue(value, "resource");
|
|
2003
|
+
const apiVersion = optionalString(resource.apiVersion);
|
|
2004
|
+
const kind = optionalString(resource.kind);
|
|
2005
|
+
if (!apiVersion || !kind) throw invalidError("resource requires apiVersion and kind");
|
|
2006
|
+
return {
|
|
2007
|
+
apiVersion,
|
|
2008
|
+
kind,
|
|
2009
|
+
metadata: metadataValue(resource.metadata),
|
|
2010
|
+
spec: objectValue(resource.spec, "resource.spec")
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
function referenceValue(value) {
|
|
2014
|
+
const reference = objectValue(value, "reference");
|
|
2015
|
+
const apiVersion = optionalString(reference.apiVersion);
|
|
2016
|
+
const kind = optionalString(reference.kind);
|
|
2017
|
+
const name = optionalString(reference.name);
|
|
2018
|
+
const uid = optionalString(reference.uid);
|
|
2019
|
+
if (!apiVersion || !kind || !name && !uid) {
|
|
2020
|
+
throw invalidError("reference requires apiVersion, kind, and name or uid");
|
|
2021
|
+
}
|
|
2022
|
+
return {
|
|
2023
|
+
apiVersion,
|
|
2024
|
+
kind,
|
|
2025
|
+
name,
|
|
2026
|
+
namespace: optionalString(reference.namespace),
|
|
2027
|
+
uid
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
function queryValue(value) {
|
|
2031
|
+
const query = objectValue(value, "query");
|
|
2032
|
+
const kind = optionalString(query.kind);
|
|
2033
|
+
if (!kind) throw invalidError("query requires kind");
|
|
2034
|
+
return {
|
|
2035
|
+
apiVersion: optionalString(query.apiVersion),
|
|
2036
|
+
kind,
|
|
2037
|
+
namespace: optionalString(query.namespace),
|
|
2038
|
+
labels: stringRecord(query.labels)
|
|
2039
|
+
};
|
|
2040
|
+
}
|
|
2041
|
+
function preconditionsValue(value) {
|
|
2042
|
+
if (value === void 0) return void 0;
|
|
2043
|
+
const preconditions = objectValue(value, "options.preconditions");
|
|
2044
|
+
return {
|
|
2045
|
+
uid: optionalString(preconditions.uid),
|
|
2046
|
+
resourceVersion: optionalString(preconditions.resourceVersion),
|
|
2047
|
+
generation: typeof preconditions.generation === "number" ? preconditions.generation : void 0
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
function applyOptions(value) {
|
|
2051
|
+
if (value === void 0) return void 0;
|
|
2052
|
+
const options = objectValue(value, "options");
|
|
2053
|
+
return {
|
|
2054
|
+
idempotencyKey: optionalString(options.idempotencyKey),
|
|
2055
|
+
fieldManager: optionalString(options.fieldManager),
|
|
2056
|
+
force: optionalBoolean(options.force),
|
|
2057
|
+
dryRun: optionalBoolean(options.dryRun),
|
|
2058
|
+
preconditions: preconditionsValue(options.preconditions)
|
|
2059
|
+
};
|
|
2060
|
+
}
|
|
2061
|
+
function getOptions(value) {
|
|
2062
|
+
if (value === void 0) return void 0;
|
|
2063
|
+
const options = objectValue(value, "options");
|
|
2064
|
+
return { resourceVersion: optionalString(options.resourceVersion) };
|
|
2065
|
+
}
|
|
2066
|
+
function listOptions(value) {
|
|
2067
|
+
if (value === void 0) return void 0;
|
|
2068
|
+
const options = objectValue(value, "options");
|
|
2069
|
+
return {
|
|
2070
|
+
resourceVersion: optionalString(options.resourceVersion),
|
|
2071
|
+
resourceVersionMatch: options.resourceVersionMatch === "exact" || options.resourceVersionMatch === "not-older-than" ? options.resourceVersionMatch : void 0,
|
|
2072
|
+
limit: typeof options.limit === "number" ? options.limit : void 0,
|
|
2073
|
+
continueToken: optionalString(options.continueToken)
|
|
2074
|
+
};
|
|
2075
|
+
}
|
|
2076
|
+
function deleteOptions(value) {
|
|
2077
|
+
if (value === void 0) return void 0;
|
|
2078
|
+
const options = objectValue(value, "options");
|
|
2079
|
+
const propagationPolicy = options.propagationPolicy;
|
|
2080
|
+
const validPropagationPolicy = propagationPolicy === "orphan" || propagationPolicy === "background" || propagationPolicy === "foreground" ? propagationPolicy : void 0;
|
|
2081
|
+
return {
|
|
2082
|
+
idempotencyKey: optionalString(options.idempotencyKey),
|
|
2083
|
+
preconditions: preconditionsValue(options.preconditions),
|
|
2084
|
+
propagationPolicy: validPropagationPolicy,
|
|
2085
|
+
dryRun: optionalBoolean(options.dryRun)
|
|
2086
|
+
};
|
|
2087
|
+
}
|
|
2088
|
+
function waitConditionValue(value) {
|
|
2089
|
+
const condition = objectValue(value, "condition");
|
|
2090
|
+
const type = optionalString(condition.type);
|
|
2091
|
+
if (!type) throw invalidError("condition requires type");
|
|
2092
|
+
const status = condition.status === "True" || condition.status === "False" || condition.status === "Unknown" ? condition.status : "True";
|
|
2093
|
+
return { type, status };
|
|
2094
|
+
}
|
|
2095
|
+
function waitOptions(value) {
|
|
2096
|
+
if (value === void 0) return {};
|
|
2097
|
+
const options = objectValue(value, "options");
|
|
2098
|
+
const timeout = typeof options.timeout === "number" ? options.timeout : void 0;
|
|
2099
|
+
const interval = typeof options.interval === "number" ? options.interval : void 0;
|
|
2100
|
+
if (timeout !== void 0 && timeout <= 0) throw invalidError("timeout must be positive");
|
|
2101
|
+
if (interval !== void 0 && interval <= 0) throw invalidError("interval must be positive");
|
|
2102
|
+
return { timeout, interval };
|
|
2103
|
+
}
|
|
2104
|
+
async function waitForResourceCondition(context, client, reference, condition, options) {
|
|
2105
|
+
return waitForCondition(
|
|
2106
|
+
() => client.get(reference, { resourceVersion: void 0 }),
|
|
2107
|
+
condition,
|
|
2108
|
+
{
|
|
2109
|
+
...options,
|
|
2110
|
+
isCancelled: () => context.isCancelled?.() === true || context.activeToolConversationId !== void 0 && context.conversationCancellation?.has(context.activeToolConversationId) === true
|
|
2111
|
+
}
|
|
2112
|
+
);
|
|
2113
|
+
}
|
|
2114
|
+
var orchestrationImpl = async (arguments_, context) => {
|
|
2115
|
+
const client = context.orchestration;
|
|
2116
|
+
if (!client) {
|
|
2117
|
+
return {
|
|
2118
|
+
error: {
|
|
2119
|
+
code: "UNSUPPORTED",
|
|
2120
|
+
message: "Orchestration manager not configured.",
|
|
2121
|
+
retryable: false
|
|
2122
|
+
}
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
try {
|
|
2126
|
+
switch (arguments_.action) {
|
|
2127
|
+
case "capabilities":
|
|
2128
|
+
return await client.getCapabilities();
|
|
2129
|
+
case "apply":
|
|
2130
|
+
return await client.apply(resourceValue(arguments_.resource), applyOptions(arguments_.options));
|
|
2131
|
+
case "get":
|
|
2132
|
+
return await client.get(referenceValue(arguments_.reference), getOptions(arguments_.options));
|
|
2133
|
+
case "list":
|
|
2134
|
+
return await client.list(queryValue(arguments_.query), listOptions(arguments_.options));
|
|
2135
|
+
case "wait":
|
|
2136
|
+
return await waitForResourceCondition(
|
|
2137
|
+
context,
|
|
2138
|
+
client,
|
|
2139
|
+
referenceValue(arguments_.reference),
|
|
2140
|
+
waitConditionValue(arguments_.condition),
|
|
2141
|
+
waitOptions(arguments_.options)
|
|
2142
|
+
);
|
|
2143
|
+
case "delete":
|
|
2144
|
+
return await client.delete(referenceValue(arguments_.reference), deleteOptions(arguments_.options));
|
|
2145
|
+
default:
|
|
2146
|
+
throw invalidError("orchestration requires a supported action");
|
|
2147
|
+
}
|
|
2148
|
+
} catch (error) {
|
|
2149
|
+
return { error: toOrchestrationErrorData(error) };
|
|
2150
|
+
}
|
|
2151
|
+
};
|
|
2152
|
+
|
|
2153
|
+
// src/tools/builtins/remoteAgent.ts
|
|
2154
|
+
var TOOL_ID3 = "remoteAgent";
|
|
2155
|
+
var REMOTE_LOG_POLL_INTERVAL_MS = 500;
|
|
2156
|
+
var REMOTE_LOG_IDLE_POLLS = 2;
|
|
2157
|
+
function messageContentToText(content) {
|
|
2158
|
+
if (typeof content === "string") return content;
|
|
2159
|
+
if (content == null) return "";
|
|
2160
|
+
try {
|
|
2161
|
+
return JSON.stringify(content);
|
|
2162
|
+
} catch {
|
|
2163
|
+
return Object.prototype.toString.call(content);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
function getRemoteStreamChunkContent(chunk) {
|
|
2167
|
+
if (chunk != null && typeof chunk === "object" && "content" in chunk) {
|
|
2168
|
+
return Reflect.get(chunk, "content");
|
|
2169
|
+
}
|
|
2170
|
+
return void 0;
|
|
2171
|
+
}
|
|
2172
|
+
function summarizeRemoteMessages(messages) {
|
|
2173
|
+
const relevant = messages.filter((message) => message.role && message.role !== "user");
|
|
2174
|
+
if (relevant.length === 0) {
|
|
2175
|
+
return "(task dispatched; waiting for remote output)";
|
|
2176
|
+
}
|
|
2177
|
+
const joined = relevant.map((message) => {
|
|
2178
|
+
const role = typeof message.role === "string" ? message.role : "message";
|
|
2179
|
+
const content = messageContentToText(message.content).trim();
|
|
2180
|
+
return content.length > 0 ? `[${role}] ${content}` : "";
|
|
2181
|
+
}).filter((line) => line.length > 0).join("\n");
|
|
2182
|
+
return joined.trim() || "(task dispatched; remote messages had no readable content)";
|
|
2183
|
+
}
|
|
2184
|
+
async function collectRemoteConversationSummary(sendRpc, nodeId, conversationId, timeoutMs) {
|
|
2185
|
+
const startedAt = Date.now();
|
|
2186
|
+
const knownMessageIds = /* @__PURE__ */ new Set();
|
|
2187
|
+
const collectedMessages = [];
|
|
2188
|
+
let idlePolls = 0;
|
|
2189
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
2190
|
+
const response = await sendRpc(nodeId, "memeloop.chat.pullAgentRunLog", {
|
|
2191
|
+
conversationId,
|
|
2192
|
+
knownMessageIds: [...knownMessageIds]
|
|
2193
|
+
});
|
|
2194
|
+
const newMessages = Array.isArray(response?.messages) ? response.messages : [];
|
|
2195
|
+
if (newMessages.length > 0) {
|
|
2196
|
+
idlePolls = 0;
|
|
2197
|
+
for (const message of newMessages) {
|
|
2198
|
+
if (typeof message.messageId === "string" && message.messageId.length > 0) {
|
|
2199
|
+
knownMessageIds.add(message.messageId);
|
|
2200
|
+
}
|
|
2201
|
+
collectedMessages.push(message);
|
|
2202
|
+
}
|
|
2203
|
+
} else if (collectedMessages.some((message) => message.role && message.role !== "user")) {
|
|
2204
|
+
idlePolls += 1;
|
|
2205
|
+
if (idlePolls >= REMOTE_LOG_IDLE_POLLS) {
|
|
2206
|
+
break;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
await new Promise((resolve) => setTimeout(resolve, REMOTE_LOG_POLL_INTERVAL_MS));
|
|
2210
|
+
}
|
|
2211
|
+
return summarizeRemoteMessages(collectedMessages);
|
|
2212
|
+
}
|
|
2213
|
+
async function supportsAgentWorkload(client) {
|
|
2214
|
+
try {
|
|
2215
|
+
const caps = await client.getCapabilities();
|
|
2216
|
+
return caps.operations.includes("apply") && caps.resourceKinds.includes("AgentWorkload");
|
|
2217
|
+
} catch {
|
|
2218
|
+
return false;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
async function runRemoteAgentViaOrchestration(client, nodeId, definitionId, message, localNodeId) {
|
|
2222
|
+
const timestamp = Date.now().toString(36);
|
|
2223
|
+
const conversationId = `remote:${nodeId}:${definitionId}:${timestamp}`;
|
|
2224
|
+
const agents = createAgentClient(client);
|
|
2225
|
+
const workload = await agents.createWorkload({
|
|
2226
|
+
name: conversationId,
|
|
2227
|
+
profileId: definitionId,
|
|
2228
|
+
promptReference: message,
|
|
2229
|
+
completionPolicy: "complete",
|
|
2230
|
+
placement: { requiredNode: nodeId }
|
|
2231
|
+
});
|
|
2232
|
+
const run = await agents.createRun({
|
|
2233
|
+
name: `${conversationId}-run`,
|
|
2234
|
+
workloadName: workload.metadata.name,
|
|
2235
|
+
promptReference: message
|
|
2236
|
+
});
|
|
2237
|
+
const result = await agents.waitForRunCondition(
|
|
2238
|
+
run.metadata.name,
|
|
2239
|
+
{ type: "Completed", status: "True" },
|
|
2240
|
+
{ timeout: 3e4, interval: 1e3 }
|
|
2241
|
+
);
|
|
2242
|
+
const finalRun = await agents.getRun(run.metadata.name);
|
|
2243
|
+
const summary = finalRun?.status?.summary ?? "(no summary)";
|
|
2244
|
+
const shortSummary = truncateToolSummary(summary);
|
|
2245
|
+
const resolvedNodeId = localNodeId?.trim() || "local";
|
|
2246
|
+
return {
|
|
2247
|
+
summary,
|
|
2248
|
+
remoteNodeId: nodeId,
|
|
2249
|
+
remoteConversationId: conversationId,
|
|
2250
|
+
definitionId,
|
|
2251
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2252
|
+
summary: shortSummary,
|
|
2253
|
+
detailRef: {
|
|
2254
|
+
type: "agent-run",
|
|
2255
|
+
conversationId,
|
|
2256
|
+
nodeId: resolvedNodeId,
|
|
2257
|
+
resourceVersion: result.observedResourceVersion
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
var remoteAgentConfigSchema = {
|
|
2263
|
+
type: "object",
|
|
2264
|
+
properties: {
|
|
2265
|
+
nodeId: { type: "string", description: "Target node ID to run the agent-run on" },
|
|
2266
|
+
definitionId: { type: "string", description: "Agent definition ID on that node" },
|
|
2267
|
+
message: { type: "string", description: "Task message for the remote agent" }
|
|
2268
|
+
},
|
|
2269
|
+
required: ["nodeId", "definitionId", "message"]
|
|
2270
|
+
};
|
|
2271
|
+
var remoteAgentListImpl = async (_arguments, context) => {
|
|
2272
|
+
if (context.orchestration) {
|
|
2273
|
+
try {
|
|
2274
|
+
const caps = await context.orchestration.getCapabilities();
|
|
2275
|
+
const targets = caps.resourceKinds.map((kind) => ({
|
|
2276
|
+
kind,
|
|
2277
|
+
interfaces: caps.interfaces,
|
|
2278
|
+
operations: caps.operations
|
|
2279
|
+
}));
|
|
2280
|
+
return {
|
|
2281
|
+
targets,
|
|
2282
|
+
capabilities: caps.interfaces
|
|
2283
|
+
};
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2286
|
+
return {
|
|
2287
|
+
targets: [],
|
|
2288
|
+
error: `Orchestration target discovery failed: ${message}`
|
|
2289
|
+
};
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
return {
|
|
2293
|
+
targets: [],
|
|
2294
|
+
error: "Direct peer enumeration is disabled. Configure an orchestration manager to discover execution targets."
|
|
2295
|
+
};
|
|
2296
|
+
};
|
|
2297
|
+
var remoteAgentImpl = async (arguments_, context) => {
|
|
2298
|
+
const nodeId = arguments_.nodeId;
|
|
2299
|
+
const definitionId = arguments_.definitionId;
|
|
2300
|
+
const message = arguments_.message;
|
|
2301
|
+
if (!nodeId || !definitionId || typeof message !== "string") {
|
|
2302
|
+
return remoteAgentListImpl(arguments_, context);
|
|
2303
|
+
}
|
|
2304
|
+
try {
|
|
2305
|
+
if (context.orchestration && await supportsAgentWorkload(context.orchestration)) {
|
|
2306
|
+
return await runRemoteAgentViaOrchestration(context.orchestration, nodeId, definitionId, message, context.localNodeId);
|
|
2307
|
+
}
|
|
2308
|
+
} catch (error) {
|
|
2309
|
+
const errorMessage = error instanceof Error ? error.message : messageContentToText(error);
|
|
2310
|
+
return { error: `remoteAgent failed: ${errorMessage}` };
|
|
2311
|
+
}
|
|
2312
|
+
const sendRpc = context.sendRpcToNode ? async (nodeId2, method, parameters) => context.sendRpcToNode?.(nodeId2, method, parameters) : void 0;
|
|
2313
|
+
if (!sendRpc) {
|
|
2314
|
+
return {
|
|
2315
|
+
error: "Remote node RPC not configured (no sendRpcToNode). Connect to peer nodes first."
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
try {
|
|
2319
|
+
const createResult = await sendRpc(nodeId, "memeloop.agent.create", {
|
|
2320
|
+
definitionId
|
|
2321
|
+
});
|
|
2322
|
+
const conversationId = createResult?.conversationId;
|
|
2323
|
+
if (!conversationId) {
|
|
2324
|
+
return { error: "Remote agent.create did not return conversationId", raw: createResult };
|
|
2325
|
+
}
|
|
2326
|
+
await sendRpc(nodeId, "memeloop.agent.send", {
|
|
2327
|
+
conversationId,
|
|
2328
|
+
message
|
|
2329
|
+
});
|
|
2330
|
+
const subscribeStream = context.subscribeRemoteStream;
|
|
2331
|
+
const streamWaitMs = context.remoteAgentStreamTimeoutMs ?? 3e4;
|
|
2332
|
+
const chunks = [];
|
|
2333
|
+
if (subscribeStream) {
|
|
2334
|
+
await new Promise((resolve) => {
|
|
2335
|
+
const unsub = subscribeStream(nodeId, conversationId, (chunk) => {
|
|
2336
|
+
if (typeof chunk === "string") chunks.push(chunk);
|
|
2337
|
+
else {
|
|
2338
|
+
const chunkContent = getRemoteStreamChunkContent(chunk);
|
|
2339
|
+
if (chunkContent !== void 0) {
|
|
2340
|
+
chunks.push(messageContentToText(chunkContent));
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
});
|
|
2344
|
+
setTimeout(() => {
|
|
2345
|
+
unsub();
|
|
2346
|
+
resolve();
|
|
2347
|
+
}, streamWaitMs);
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
const fullSummary = chunks.length > 0 ? chunks.join("").trim() : await collectRemoteConversationSummary(sendRpc, nodeId, conversationId, streamWaitMs);
|
|
2351
|
+
const shortSummary = truncateToolSummary(fullSummary);
|
|
2352
|
+
return {
|
|
2353
|
+
summary: fullSummary,
|
|
2354
|
+
remoteNodeId: nodeId,
|
|
2355
|
+
remoteConversationId: conversationId,
|
|
2356
|
+
definitionId,
|
|
2357
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2358
|
+
summary: shortSummary,
|
|
2359
|
+
detailRef: {
|
|
2360
|
+
type: "agent-run",
|
|
2361
|
+
conversationId,
|
|
2362
|
+
nodeId
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
};
|
|
2366
|
+
} catch (error) {
|
|
2367
|
+
const message2 = error instanceof Error ? error.message : messageContentToText(error);
|
|
2368
|
+
return { error: `remoteAgent failed: ${message2}` };
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
function getRemoteAgentToolId() {
|
|
2372
|
+
return TOOL_ID3;
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
// src/tools/builtins/spawnAgent.ts
|
|
2376
|
+
var TOOL_ID4 = "spawnAgent";
|
|
2377
|
+
async function supportsAgentWorkload2(client) {
|
|
2378
|
+
try {
|
|
2379
|
+
const caps = await client.getCapabilities();
|
|
2380
|
+
return caps.operations.includes("apply") && caps.resourceKinds.includes("AgentWorkload");
|
|
2381
|
+
} catch {
|
|
2382
|
+
return false;
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
async function runSpawnAgentViaOrchestration(client, definitionId, message, conversationId, localNodeId) {
|
|
2386
|
+
const agents = createAgentClient(client);
|
|
2387
|
+
const workload = await agents.createWorkload({
|
|
2388
|
+
name: conversationId,
|
|
2389
|
+
profileId: definitionId,
|
|
2390
|
+
completionPolicy: "complete"
|
|
2391
|
+
});
|
|
2392
|
+
const run = await agents.createRun({
|
|
2393
|
+
name: `${conversationId}-run`,
|
|
2394
|
+
workloadName: workload.metadata.name,
|
|
2395
|
+
promptReference: message
|
|
2396
|
+
});
|
|
2397
|
+
const result = await agents.waitForRunCondition(
|
|
2398
|
+
run.metadata.name,
|
|
2399
|
+
{ type: "Completed", status: "True" },
|
|
2400
|
+
{ timeout: 3e4, interval: 1e3 }
|
|
2401
|
+
);
|
|
2402
|
+
const finalRun = await agents.getRun(run.metadata.name);
|
|
2403
|
+
const summary = finalRun?.status?.summary ?? "(no summary)";
|
|
2404
|
+
const shortSummary = truncateToolSummary(summary);
|
|
2405
|
+
const nodeId = localNodeId?.trim() || "local";
|
|
2406
|
+
return {
|
|
2407
|
+
summary,
|
|
2408
|
+
conversationId,
|
|
2409
|
+
definitionId,
|
|
2410
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2411
|
+
summary: shortSummary,
|
|
2412
|
+
detailRef: {
|
|
2413
|
+
type: "agent-run",
|
|
2414
|
+
conversationId,
|
|
2415
|
+
nodeId,
|
|
2416
|
+
resourceVersion: result.observedResourceVersion
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
async function runSpawnAgentLocally(runLocalAgent, definitionId, message, conversationId, localNodeId) {
|
|
2422
|
+
const chunks = [];
|
|
2423
|
+
for await (const step of runLocalAgent({ conversationId, message })) {
|
|
2424
|
+
if (step.type === "message" && typeof step.data === "string") {
|
|
2425
|
+
chunks.push(step.data);
|
|
2426
|
+
}
|
|
2427
|
+
if (step.type === "message" && step.data != null && typeof step.data === "object" && "content" in step.data) {
|
|
2428
|
+
const c = step.data.content;
|
|
2429
|
+
if (typeof c === "string") chunks.push(c);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
const fullSummary = chunks.join("").trim() || "(no text output)";
|
|
2433
|
+
const shortSummary = truncateToolSummary(fullSummary);
|
|
2434
|
+
const nodeId = localNodeId?.trim() || "local";
|
|
2435
|
+
return {
|
|
2436
|
+
summary: fullSummary,
|
|
2437
|
+
conversationId,
|
|
2438
|
+
definitionId,
|
|
2439
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2440
|
+
summary: shortSummary,
|
|
2441
|
+
detailRef: {
|
|
2442
|
+
type: "agent-run",
|
|
2443
|
+
conversationId,
|
|
2444
|
+
nodeId
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
var spawnAgentConfigSchema = {
|
|
2450
|
+
type: "object",
|
|
2451
|
+
properties: {
|
|
2452
|
+
definitionId: { type: "string", description: "Agent definition ID to use for the agent-run" },
|
|
2453
|
+
message: { type: "string", description: "User message / task for the agent-run" }
|
|
2454
|
+
},
|
|
2455
|
+
required: ["definitionId", "message"]
|
|
2456
|
+
};
|
|
2457
|
+
var spawnAgentImpl = async (arguments_, context) => {
|
|
2458
|
+
const definitionId = arguments_.definitionId;
|
|
2459
|
+
const message = arguments_.message;
|
|
2460
|
+
if (!definitionId || typeof message !== "string") {
|
|
2461
|
+
return { error: "spawnAgent requires definitionId and message" };
|
|
2462
|
+
}
|
|
2463
|
+
const conversationId = `spawn:${definitionId}:${Date.now().toString(36)}`;
|
|
2464
|
+
try {
|
|
2465
|
+
if (context.orchestration && await supportsAgentWorkload2(context.orchestration)) {
|
|
2466
|
+
return await runSpawnAgentViaOrchestration(context.orchestration, definitionId, message, conversationId, context.localNodeId);
|
|
2467
|
+
}
|
|
2468
|
+
if (!context.runLocalAgent) {
|
|
2469
|
+
return {
|
|
2470
|
+
error: "Local agent runner not configured (no runLocalAgent in context)."
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
return await runSpawnAgentLocally(
|
|
2474
|
+
(input) => context.runLocalAgent(input),
|
|
2475
|
+
definitionId,
|
|
2476
|
+
message,
|
|
2477
|
+
conversationId,
|
|
2478
|
+
context.localNodeId
|
|
2479
|
+
);
|
|
2480
|
+
} catch (error) {
|
|
2481
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2482
|
+
return { error: `spawnAgent failed: ${errorMessage}`, conversationId };
|
|
2483
|
+
}
|
|
2484
|
+
};
|
|
2485
|
+
function getSpawnAgentToolId() {
|
|
2486
|
+
return TOOL_ID4;
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
// src/agent/agentProfiles.ts
|
|
2490
|
+
function makeBuiltinDefinition(id, name, type, prompt, permissions, model) {
|
|
2491
|
+
const systemPrompt = prompt;
|
|
2492
|
+
const tools = [];
|
|
2493
|
+
return {
|
|
2494
|
+
id,
|
|
2495
|
+
name,
|
|
2496
|
+
type,
|
|
2497
|
+
prompt,
|
|
2498
|
+
permissions,
|
|
2499
|
+
model,
|
|
2500
|
+
protocolDef: {
|
|
2501
|
+
id,
|
|
2502
|
+
name,
|
|
2503
|
+
description: prompt.slice(0, 200),
|
|
2504
|
+
systemPrompt,
|
|
2505
|
+
tools,
|
|
2506
|
+
version: "1.0.0",
|
|
2507
|
+
modelConfig: model ? {
|
|
2508
|
+
provider: model.split("/")[0] ?? "memeloop",
|
|
2509
|
+
model: model.split("/").slice(1).join("/") || model
|
|
2510
|
+
} : void 0
|
|
2511
|
+
}
|
|
2512
|
+
};
|
|
2513
|
+
}
|
|
2514
|
+
var buildAgent = makeBuiltinDefinition(
|
|
2515
|
+
"memeloop:build",
|
|
2516
|
+
"Build Agent",
|
|
2517
|
+
"build",
|
|
2518
|
+
"You are a build agent capable of executing tasks, writing and editing files, running commands, and making changes. Use tools to accomplish the user's goals efficiently.",
|
|
2519
|
+
{ default: "allow", rules: [] }
|
|
2520
|
+
);
|
|
2521
|
+
var planAgent = makeBuiltinDefinition(
|
|
2522
|
+
"memeloop:plan",
|
|
2523
|
+
"Plan Agent",
|
|
2524
|
+
"plan",
|
|
2525
|
+
"You are a planning agent. Your role is to analyze requirements, decompose tasks, and create structured plans. You CANNOT write files or execute terminal commands. Only use read and search tools.",
|
|
2526
|
+
{
|
|
2527
|
+
default: "deny",
|
|
2528
|
+
rules: [
|
|
2529
|
+
{ pattern: "file.read", action: "allow" },
|
|
2530
|
+
{ pattern: "file.search", action: "allow" },
|
|
2531
|
+
{ pattern: "file.list", action: "allow" },
|
|
2532
|
+
{ pattern: "grep.search", action: "allow" },
|
|
2533
|
+
{ pattern: "glob.*", action: "allow" }
|
|
2534
|
+
]
|
|
2535
|
+
}
|
|
2536
|
+
);
|
|
2537
|
+
var exploreAgent = makeBuiltinDefinition(
|
|
2538
|
+
"memeloop:explore",
|
|
2539
|
+
"Explore Agent",
|
|
2540
|
+
"explore",
|
|
2541
|
+
"You are an exploration agent specialized in fast codebase search and discovery. You have read and search tools. Do NOT modify files or run terminal commands. Focus on finding relevant code, files, and patterns.",
|
|
2542
|
+
{
|
|
2543
|
+
default: "deny",
|
|
2544
|
+
rules: [
|
|
2545
|
+
{ pattern: "file.read", action: "allow" },
|
|
2546
|
+
{ pattern: "file.search", action: "allow" },
|
|
2547
|
+
{ pattern: "file.list", action: "allow" },
|
|
2548
|
+
{ pattern: "grep.search", action: "allow" },
|
|
2549
|
+
{ pattern: "glob.*", action: "allow" },
|
|
2550
|
+
{ pattern: "lsp.*", action: "allow" }
|
|
2551
|
+
]
|
|
2552
|
+
}
|
|
2553
|
+
);
|
|
2554
|
+
var oracleAgent = makeBuiltinDefinition(
|
|
2555
|
+
"memeloop:oracle",
|
|
2556
|
+
"Oracle Agent",
|
|
2557
|
+
"oracle",
|
|
2558
|
+
"You are an oracle agent specialized in architecture analysis, code review, and constraint verification. You have read access only. Review code, identify issues, and provide expert architectural guidance.",
|
|
2559
|
+
{
|
|
2560
|
+
default: "deny",
|
|
2561
|
+
rules: [
|
|
2562
|
+
{ pattern: "file.read", action: "allow" },
|
|
2563
|
+
{ pattern: "file.search", action: "allow" },
|
|
2564
|
+
{ pattern: "file.list", action: "allow" },
|
|
2565
|
+
{ pattern: "grep.search", action: "allow" },
|
|
2566
|
+
{ pattern: "glob.*", action: "allow" },
|
|
2567
|
+
{ pattern: "lsp.*", action: "allow" }
|
|
2568
|
+
]
|
|
2569
|
+
}
|
|
2570
|
+
);
|
|
2571
|
+
var librarianAgent = makeBuiltinDefinition(
|
|
2572
|
+
"memeloop:librarian",
|
|
2573
|
+
"Librarian Agent",
|
|
2574
|
+
"librarian",
|
|
2575
|
+
"You are a librarian agent specialized in external documentation lookup, web search, and context gathering. Use web search tools to find relevant documentation, APIs, and examples. Do NOT modify files or run terminal commands.",
|
|
2576
|
+
{
|
|
2577
|
+
default: "deny",
|
|
2578
|
+
rules: [
|
|
2579
|
+
{ pattern: "file.read", action: "allow" },
|
|
2580
|
+
{ pattern: "file.search", action: "allow" },
|
|
2581
|
+
{ pattern: "file.list", action: "allow" },
|
|
2582
|
+
{ pattern: "web.*", action: "allow" },
|
|
2583
|
+
{ pattern: "grep.search", action: "allow" },
|
|
2584
|
+
{ pattern: "glob.*", action: "allow" }
|
|
2585
|
+
]
|
|
2586
|
+
}
|
|
2587
|
+
);
|
|
2588
|
+
var BUILTIN_AGENT_PROFILES = [
|
|
2589
|
+
buildAgent,
|
|
2590
|
+
planAgent,
|
|
2591
|
+
exploreAgent,
|
|
2592
|
+
oracleAgent,
|
|
2593
|
+
librarianAgent
|
|
2594
|
+
];
|
|
2595
|
+
|
|
2596
|
+
// src/agent/agentProfileRegistry.ts
|
|
2597
|
+
var AgentProfileRegistry = class {
|
|
2598
|
+
profiles = /* @__PURE__ */ new Map();
|
|
2599
|
+
constructor() {
|
|
2600
|
+
this.seedDefaults();
|
|
2601
|
+
}
|
|
2602
|
+
/** Seed the registry with built-in agent profiles. */
|
|
2603
|
+
seedDefaults() {
|
|
2604
|
+
for (const profile of BUILTIN_AGENT_PROFILES) {
|
|
2605
|
+
this.profiles.set(profile.id, profile);
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
/**
|
|
2609
|
+
* Register a new agent profile or override an existing one.
|
|
2610
|
+
* Throws if the profile is invalid.
|
|
2611
|
+
*/
|
|
2612
|
+
registerAgentProfile(profile) {
|
|
2613
|
+
if (!profile.id || typeof profile.id !== "string" || profile.id.trim().length === 0) {
|
|
2614
|
+
throw new Error("Agent profile must have a non-empty id");
|
|
2615
|
+
}
|
|
2616
|
+
if (!profile.name || typeof profile.name !== "string") {
|
|
2617
|
+
throw new Error("Agent profile must have a name");
|
|
2618
|
+
}
|
|
2619
|
+
if (!profile.type || typeof profile.type !== "string") {
|
|
2620
|
+
throw new Error("Agent profile must have a type");
|
|
2621
|
+
}
|
|
2622
|
+
if (!profile.prompt || typeof profile.prompt !== "string") {
|
|
2623
|
+
throw new Error("Agent profile must have a prompt");
|
|
2624
|
+
}
|
|
2625
|
+
if (!profile.permissions || typeof profile.permissions.default !== "string") {
|
|
2626
|
+
throw new Error("Agent profile must have valid permissions");
|
|
2627
|
+
}
|
|
2628
|
+
this.profiles.set(profile.id, profile);
|
|
2629
|
+
}
|
|
2630
|
+
/**
|
|
2631
|
+
* Get an agent profile by ID.
|
|
2632
|
+
* Returns undefined if not found.
|
|
2633
|
+
*/
|
|
2634
|
+
getAgentProfile(id) {
|
|
2635
|
+
return this.profiles.get(id);
|
|
2636
|
+
}
|
|
2637
|
+
/**
|
|
2638
|
+
* List all registered agent profiles.
|
|
2639
|
+
*/
|
|
2640
|
+
listAgentProfiles() {
|
|
2641
|
+
return Array.from(this.profiles.values());
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* List agent profiles filtered by type.
|
|
2645
|
+
*/
|
|
2646
|
+
listAgentProfilesByType(type) {
|
|
2647
|
+
return this.listAgentProfiles().filter((profile) => profile.type === type);
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Remove an agent profile by ID.
|
|
2651
|
+
*/
|
|
2652
|
+
unregisterAgentProfile(id) {
|
|
2653
|
+
return this.profiles.delete(id);
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* Reset the registry to only built-in defaults.
|
|
2657
|
+
*/
|
|
2658
|
+
reset() {
|
|
2659
|
+
this.profiles.clear();
|
|
2660
|
+
this.seedDefaults();
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
var defaultRegistry = null;
|
|
2664
|
+
function getAgentProfileRegistry() {
|
|
2665
|
+
if (!defaultRegistry) {
|
|
2666
|
+
defaultRegistry = new AgentProfileRegistry();
|
|
2667
|
+
}
|
|
2668
|
+
return defaultRegistry;
|
|
2669
|
+
}
|
|
2670
|
+
function resetAgentProfileRegistry() {
|
|
2671
|
+
if (defaultRegistry) {
|
|
2672
|
+
defaultRegistry.reset();
|
|
2673
|
+
}
|
|
2674
|
+
defaultRegistry = null;
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
// src/tools/builtins/task.ts
|
|
2678
|
+
var TOOL_ID5 = "task";
|
|
2679
|
+
async function supportsAgentWorkload3(client) {
|
|
2680
|
+
try {
|
|
2681
|
+
const caps = await client.getCapabilities();
|
|
2682
|
+
return caps.operations.includes("apply") && caps.resourceKinds.includes("AgentWorkload");
|
|
2683
|
+
} catch {
|
|
2684
|
+
return false;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
async function runTaskViaOrchestration(client, agentId, prompt, background, localNodeId, conversationId, permissions) {
|
|
2688
|
+
const agents = createAgentClient(client);
|
|
2689
|
+
const workload = await agents.createWorkload({
|
|
2690
|
+
name: conversationId,
|
|
2691
|
+
profileId: agentId,
|
|
2692
|
+
promptReference: prompt,
|
|
2693
|
+
completionPolicy: background ? "detach" : "complete",
|
|
2694
|
+
toolPolicy: {
|
|
2695
|
+
defaultAction: permissions.default,
|
|
2696
|
+
rules: permissions.rules
|
|
2697
|
+
}
|
|
2698
|
+
});
|
|
2699
|
+
const run = await agents.createRun({
|
|
2700
|
+
name: `${conversationId}-run`,
|
|
2701
|
+
workloadName: workload.metadata.name,
|
|
2702
|
+
promptReference: prompt
|
|
2703
|
+
});
|
|
2704
|
+
const nodeId = localNodeId?.trim() || "local";
|
|
2705
|
+
if (background) {
|
|
2706
|
+
return {
|
|
2707
|
+
summary: `Background task "${agentId}" launched. Task ID: ${conversationId}`,
|
|
2708
|
+
conversationId,
|
|
2709
|
+
agentId,
|
|
2710
|
+
taskId: conversationId,
|
|
2711
|
+
background: true,
|
|
2712
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2713
|
+
summary: `[bg-task] ${agentId}: ${conversationId}`,
|
|
2714
|
+
detailRef: {
|
|
2715
|
+
type: "agent-run",
|
|
2716
|
+
conversationId,
|
|
2717
|
+
nodeId,
|
|
2718
|
+
resourceVersion: run.metadata.resourceVersion
|
|
2719
|
+
}
|
|
2720
|
+
}
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
const result = await agents.waitForRunCondition(
|
|
2724
|
+
run.metadata.name,
|
|
2725
|
+
{ type: "Completed", status: "True" },
|
|
2726
|
+
{ timeout: 3e4, interval: 1e3 }
|
|
2727
|
+
);
|
|
2728
|
+
const finalRun = await agents.getRun(run.metadata.name);
|
|
2729
|
+
const text = finalRun?.status?.summary ?? "(no summary)";
|
|
2730
|
+
const shortSummary = truncateToolSummary(text);
|
|
2731
|
+
return {
|
|
2732
|
+
result: text,
|
|
2733
|
+
conversationId,
|
|
2734
|
+
agentId,
|
|
2735
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2736
|
+
summary: shortSummary,
|
|
2737
|
+
detailRef: {
|
|
2738
|
+
type: "agent-run",
|
|
2739
|
+
conversationId,
|
|
2740
|
+
nodeId,
|
|
2741
|
+
resourceVersion: result.observedResourceVersion
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
async function runTaskLocally(runLocalAgent, context, agentId, prompt, background, conversationId) {
|
|
2747
|
+
async function collectOutput(gen2) {
|
|
2748
|
+
const chunks = [];
|
|
2749
|
+
for await (const step of gen2) {
|
|
2750
|
+
if (step.type === "message") {
|
|
2751
|
+
if (typeof step.data === "string") {
|
|
2752
|
+
chunks.push(step.data);
|
|
2753
|
+
} else if (step.data != null && typeof step.data === "object" && "content" in step.data) {
|
|
2754
|
+
const c = step.data.content;
|
|
2755
|
+
if (typeof c === "string") chunks.push(c);
|
|
2756
|
+
}
|
|
2757
|
+
}
|
|
2758
|
+
}
|
|
2759
|
+
return { text: chunks.join("").trim() || "(no text output)", conversationId };
|
|
2760
|
+
}
|
|
2761
|
+
if (background) {
|
|
2762
|
+
const gen2 = runLocalAgent({ conversationId, message: prompt });
|
|
2763
|
+
void collectOutput(gen2).catch(() => {
|
|
2764
|
+
});
|
|
2765
|
+
const nodeId2 = context.localNodeId?.trim() || "local";
|
|
2766
|
+
return {
|
|
2767
|
+
summary: `Background task "${agentId}" launched. Task ID: ${conversationId}`,
|
|
2768
|
+
conversationId,
|
|
2769
|
+
agentId,
|
|
2770
|
+
taskId: conversationId,
|
|
2771
|
+
background: true,
|
|
2772
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2773
|
+
summary: `[bg-task] ${agentId}: ${conversationId}`,
|
|
2774
|
+
detailRef: {
|
|
2775
|
+
type: "agent-run",
|
|
2776
|
+
conversationId,
|
|
2777
|
+
nodeId: nodeId2
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
const gen = runLocalAgent({ conversationId, message: prompt });
|
|
2783
|
+
const { text, conversationId: cid } = await collectOutput(gen);
|
|
2784
|
+
const shortSummary = truncateToolSummary(text);
|
|
2785
|
+
const nodeId = context.localNodeId?.trim() || "local";
|
|
2786
|
+
return {
|
|
2787
|
+
result: text,
|
|
2788
|
+
conversationId: cid,
|
|
2789
|
+
agentId,
|
|
2790
|
+
[MEMELOOP_STRUCTURED_TOOL_KEY]: {
|
|
2791
|
+
summary: shortSummary,
|
|
2792
|
+
detailRef: {
|
|
2793
|
+
type: "agent-run",
|
|
2794
|
+
conversationId: cid,
|
|
2795
|
+
nodeId
|
|
2796
|
+
}
|
|
2797
|
+
}
|
|
2798
|
+
};
|
|
2799
|
+
}
|
|
2800
|
+
var taskToolConfigSchema = {
|
|
2801
|
+
type: "object",
|
|
2802
|
+
properties: {
|
|
2803
|
+
agent: {
|
|
2804
|
+
type: "string",
|
|
2805
|
+
description: "Agent ID to delegate to (e.g. 'memeloop:build', 'memeloop:explore')"
|
|
2806
|
+
},
|
|
2807
|
+
prompt: {
|
|
2808
|
+
type: "string",
|
|
2809
|
+
description: "Task prompt / instructions for the delegated agent"
|
|
2810
|
+
},
|
|
2811
|
+
background: {
|
|
2812
|
+
type: "boolean",
|
|
2813
|
+
description: "If true, runs asynchronously and returns a task ID immediately"
|
|
2814
|
+
}
|
|
2815
|
+
},
|
|
2816
|
+
required: ["agent", "prompt"]
|
|
2817
|
+
};
|
|
2818
|
+
function isTooDeeplyNested(context) {
|
|
2819
|
+
const cid = context.activeToolConversationId;
|
|
2820
|
+
if (!cid) return false;
|
|
2821
|
+
const depth = cid.split(":").length - 1;
|
|
2822
|
+
return depth > 2;
|
|
2823
|
+
}
|
|
2824
|
+
function applyAgentPermissions(context, agentId, defaultAction, rules) {
|
|
2825
|
+
const tp = context.agentToolLoop ?? (context.agentToolLoop = {});
|
|
2826
|
+
const tperm = tp.toolPermissions ?? (tp.toolPermissions = {});
|
|
2827
|
+
const perAgent = tperm.perAgent ?? (tperm.perAgent = {});
|
|
2828
|
+
perAgent[agentId] = { default: defaultAction, rules };
|
|
2829
|
+
}
|
|
2830
|
+
var taskToolImpl = async (arguments_, context) => {
|
|
2831
|
+
const agentId = arguments_.agent;
|
|
2832
|
+
const prompt = arguments_.prompt;
|
|
2833
|
+
const background = arguments_.background;
|
|
2834
|
+
if (!agentId || typeof prompt !== "string" || prompt.trim().length === 0) {
|
|
2835
|
+
return { error: "task requires 'agent' (string) and 'prompt' (non-empty string)" };
|
|
2836
|
+
}
|
|
2837
|
+
if (isTooDeeplyNested(context)) {
|
|
2838
|
+
return {
|
|
2839
|
+
error: "Maximum agent nesting depth exceeded. Cannot delegate further."
|
|
2840
|
+
};
|
|
2841
|
+
}
|
|
2842
|
+
const registry = getAgentProfileRegistry();
|
|
2843
|
+
const agentProfile = registry.getAgentProfile(agentId);
|
|
2844
|
+
if (!agentProfile) {
|
|
2845
|
+
const available = registry.listAgentProfiles().map((a) => a.id).join(", ");
|
|
2846
|
+
return {
|
|
2847
|
+
error: `Agent "${agentId}" not found in registry. Available: [${available}]`
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2850
|
+
const permissions = {
|
|
2851
|
+
default: agentProfile.permissions.default,
|
|
2852
|
+
rules: agentProfile.permissions.rules
|
|
2853
|
+
};
|
|
2854
|
+
const timestamp = Date.now().toString(36);
|
|
2855
|
+
const conversationId = `${agentProfile.id}:${timestamp}`;
|
|
2856
|
+
try {
|
|
2857
|
+
if (context.orchestration && await supportsAgentWorkload3(context.orchestration)) {
|
|
2858
|
+
return await runTaskViaOrchestration(
|
|
2859
|
+
context.orchestration,
|
|
2860
|
+
agentProfile.id,
|
|
2861
|
+
prompt,
|
|
2862
|
+
background,
|
|
2863
|
+
context.localNodeId,
|
|
2864
|
+
conversationId,
|
|
2865
|
+
permissions
|
|
2866
|
+
);
|
|
2867
|
+
}
|
|
2868
|
+
if (!context.runLocalAgent) {
|
|
2869
|
+
return {
|
|
2870
|
+
error: "Local agent runner not configured (no runLocalAgent in context)."
|
|
2871
|
+
};
|
|
2872
|
+
}
|
|
2873
|
+
applyAgentPermissions(
|
|
2874
|
+
context,
|
|
2875
|
+
agentProfile.id,
|
|
2876
|
+
permissions.default,
|
|
2877
|
+
permissions.rules
|
|
2878
|
+
);
|
|
2879
|
+
return await runTaskLocally(
|
|
2880
|
+
(input) => context.runLocalAgent(input),
|
|
2881
|
+
context,
|
|
2882
|
+
agentProfile.id,
|
|
2883
|
+
prompt,
|
|
2884
|
+
background,
|
|
2885
|
+
conversationId
|
|
2886
|
+
);
|
|
2887
|
+
} catch (error) {
|
|
2888
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2889
|
+
return {
|
|
2890
|
+
error: `Task execution failed: ${message}`,
|
|
2891
|
+
conversationId,
|
|
2892
|
+
agentId: agentProfile.id
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
};
|
|
2896
|
+
function getTaskToolId() {
|
|
2897
|
+
return TOOL_ID5;
|
|
2898
|
+
}
|
|
2899
|
+
|
|
2900
|
+
// src/tools/builtins/todoWrite.ts
|
|
2901
|
+
import { z as z3 } from "zod";
|
|
2902
|
+
var todoWriteConfigSchema = z3.object({
|
|
2903
|
+
action: z3.enum(["create", "update", "complete", "list", "remove"]).describe("Action: create, update, complete, list, or remove"),
|
|
2904
|
+
id: z3.string().min(1).optional().describe("Todo item ID (required for update/complete/remove)"),
|
|
2905
|
+
content: z3.string().min(1).optional().describe("Todo item content (required for create/update)"),
|
|
2906
|
+
status: z3.enum(["pending", "in_progress", "completed", "cancelled"]).optional().describe("Status (defaults to 'pending' for create)"),
|
|
2907
|
+
priority: z3.enum(["high", "medium", "low"]).optional().default("medium").describe("Priority level")
|
|
2908
|
+
});
|
|
2909
|
+
var TODO_WRITE_TOOL_ID = "todoWrite";
|
|
2910
|
+
var conversationTodos = /* @__PURE__ */ new Map();
|
|
2911
|
+
function __clearTodoStore() {
|
|
2912
|
+
conversationTodos.clear();
|
|
2913
|
+
}
|
|
2914
|
+
function getConversationTodos(conversationId) {
|
|
2915
|
+
let todos = conversationTodos.get(conversationId);
|
|
2916
|
+
if (!todos) {
|
|
2917
|
+
todos = /* @__PURE__ */ new Map();
|
|
2918
|
+
conversationTodos.set(conversationId, todos);
|
|
2919
|
+
}
|
|
2920
|
+
return todos;
|
|
2921
|
+
}
|
|
2922
|
+
function formatTodoList(todos) {
|
|
2923
|
+
if (todos.size === 0) {
|
|
2924
|
+
return "(No todos)";
|
|
2925
|
+
}
|
|
2926
|
+
const statusOrder = {
|
|
2927
|
+
in_progress: 0,
|
|
2928
|
+
pending: 1,
|
|
2929
|
+
completed: 2,
|
|
2930
|
+
cancelled: 3
|
|
2931
|
+
};
|
|
2932
|
+
const sorted = [...todos.values()].sort(
|
|
2933
|
+
(a, b) => (statusOrder[a.status] ?? 99) - (statusOrder[b.status] ?? 99) || b.updatedAt - a.updatedAt
|
|
2934
|
+
);
|
|
2935
|
+
const statusIcons = {
|
|
2936
|
+
pending: "\u25CB",
|
|
2937
|
+
in_progress: "\u25C9",
|
|
2938
|
+
completed: "\u2713",
|
|
2939
|
+
cancelled: "\u2717"
|
|
2940
|
+
};
|
|
2941
|
+
return sorted.map(
|
|
2942
|
+
(t) => `${statusIcons[t.status] ?? "?"} [${t.priority}] ${t.content} (id: ${t.id})`
|
|
2943
|
+
).join("\n");
|
|
2944
|
+
}
|
|
2945
|
+
function getConversationId(context) {
|
|
2946
|
+
return context.agent?.id ?? context.activeToolConversationId ?? "default";
|
|
2947
|
+
}
|
|
2948
|
+
async function todoWriteImpl(arguments_, context) {
|
|
2949
|
+
const parsed = todoWriteConfigSchema.safeParse(arguments_);
|
|
2950
|
+
if (!parsed.success) {
|
|
2951
|
+
return { error: `invalid_todoWrite_args: ${parsed.error.message}` };
|
|
2952
|
+
}
|
|
2953
|
+
const { action, id, content, status, priority } = parsed.data;
|
|
2954
|
+
const conversationId = getConversationId(context);
|
|
2955
|
+
const todos = getConversationTodos(conversationId);
|
|
2956
|
+
const now = Date.now();
|
|
2957
|
+
switch (action) {
|
|
2958
|
+
case "create": {
|
|
2959
|
+
if (!content) {
|
|
2960
|
+
return { error: "content is required for create action" };
|
|
2961
|
+
}
|
|
2962
|
+
const newId = id ?? crypto.randomUUID();
|
|
2963
|
+
if (todos.has(newId)) {
|
|
2964
|
+
return { error: `Todo with id '${newId}' already exists. Use update action.` };
|
|
2965
|
+
}
|
|
2966
|
+
const item = {
|
|
2967
|
+
id: newId,
|
|
2968
|
+
content,
|
|
2969
|
+
status: status ?? "pending",
|
|
2970
|
+
priority,
|
|
2971
|
+
createdAt: now,
|
|
2972
|
+
updatedAt: now
|
|
2973
|
+
};
|
|
2974
|
+
todos.set(newId, item);
|
|
2975
|
+
return {
|
|
2976
|
+
result: `Todo created: [${item.priority}] ${item.content} (id: ${item.id})
|
|
2977
|
+
|
|
2978
|
+
${formatTodoList(todos)}`
|
|
2979
|
+
};
|
|
2980
|
+
}
|
|
2981
|
+
case "update": {
|
|
2982
|
+
if (!id) {
|
|
2983
|
+
return { error: "id is required for update action" };
|
|
2984
|
+
}
|
|
2985
|
+
const existing = todos.get(id);
|
|
2986
|
+
if (!existing) {
|
|
2987
|
+
return { error: `Todo with id '${id}' not found` };
|
|
2988
|
+
}
|
|
2989
|
+
if (content !== void 0) existing.content = content;
|
|
2990
|
+
if (status !== void 0) existing.status = status;
|
|
2991
|
+
existing.priority = priority ?? existing.priority;
|
|
2992
|
+
existing.updatedAt = now;
|
|
2993
|
+
return {
|
|
2994
|
+
result: `Todo updated: [${existing.priority}] ${existing.content} (id: ${existing.id}, status: ${existing.status})
|
|
2995
|
+
|
|
2996
|
+
${formatTodoList(todos)}`
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
case "complete": {
|
|
3000
|
+
if (!id) {
|
|
3001
|
+
return { error: "id is required for complete action" };
|
|
3002
|
+
}
|
|
3003
|
+
const existing = todos.get(id);
|
|
3004
|
+
if (!existing) {
|
|
3005
|
+
return { error: `Todo with id '${id}' not found` };
|
|
3006
|
+
}
|
|
3007
|
+
existing.status = "completed";
|
|
3008
|
+
existing.updatedAt = now;
|
|
3009
|
+
return {
|
|
3010
|
+
result: `Todo completed: [${existing.priority}] ${existing.content} (id: ${existing.id})
|
|
3011
|
+
|
|
3012
|
+
${formatTodoList(todos)}`
|
|
3013
|
+
};
|
|
3014
|
+
}
|
|
3015
|
+
case "remove": {
|
|
3016
|
+
if (!id) {
|
|
3017
|
+
let removed2 = 0;
|
|
3018
|
+
for (const [key, item] of todos) {
|
|
3019
|
+
if (item.status === "completed" || item.status === "cancelled") {
|
|
3020
|
+
todos.delete(key);
|
|
3021
|
+
removed2++;
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
return {
|
|
3025
|
+
result: `Removed ${removed2} completed/cancelled todo(s)
|
|
3026
|
+
|
|
3027
|
+
${formatTodoList(todos)}`
|
|
3028
|
+
};
|
|
3029
|
+
}
|
|
3030
|
+
const removed = todos.delete(id);
|
|
3031
|
+
return {
|
|
3032
|
+
result: removed ? `Todo removed: ${id}
|
|
3033
|
+
|
|
3034
|
+
${formatTodoList(todos)}` : `Todo with id '${id}' not found
|
|
3035
|
+
|
|
3036
|
+
${formatTodoList(todos)}`
|
|
3037
|
+
};
|
|
3038
|
+
}
|
|
3039
|
+
case "list":
|
|
3040
|
+
default: {
|
|
3041
|
+
return {
|
|
3042
|
+
result: `Todo list (${todos.size} items):
|
|
3043
|
+
|
|
3044
|
+
${formatTodoList(todos)}`
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
// src/loopAPI/plugins/builtinToolsPlugin.ts
|
|
3051
|
+
var PLUGIN_MCP_CLIENT = "builtin:mcp-client";
|
|
3052
|
+
var PLUGIN_MCP_FORWARD = "builtin:mcp-forward";
|
|
3053
|
+
var PLUGIN_ORCHESTRATION = "builtin:orchestration";
|
|
3054
|
+
var PLUGIN_SPAWN_AGENT = "builtin:spawn-agent";
|
|
3055
|
+
var PLUGIN_REMOTE_AGENT = "builtin:remote-agent";
|
|
3056
|
+
var PLUGIN_ASK_QUESTION = "builtin:ask-question";
|
|
3057
|
+
var PLUGIN_TODO_WRITE = "builtin:todo-write";
|
|
3058
|
+
var PLUGIN_ASK_USER_QUESTION = "builtin:ask-user-question";
|
|
3059
|
+
var PLUGIN_TASK = "builtin:task";
|
|
3060
|
+
var BUILTIN_TOOL_PLUGIN_IDS = [
|
|
3061
|
+
PLUGIN_MCP_CLIENT,
|
|
3062
|
+
PLUGIN_MCP_FORWARD,
|
|
3063
|
+
PLUGIN_ORCHESTRATION,
|
|
3064
|
+
PLUGIN_SPAWN_AGENT,
|
|
3065
|
+
PLUGIN_REMOTE_AGENT,
|
|
3066
|
+
PLUGIN_ASK_QUESTION,
|
|
3067
|
+
PLUGIN_TODO_WRITE,
|
|
3068
|
+
PLUGIN_ASK_USER_QUESTION,
|
|
3069
|
+
PLUGIN_TASK
|
|
3070
|
+
];
|
|
3071
|
+
function getToolRegistry(context) {
|
|
3072
|
+
return context.toolRegistry;
|
|
3073
|
+
}
|
|
3074
|
+
function createBuiltinToolPlugin(options) {
|
|
3075
|
+
return {
|
|
3076
|
+
id: options.id,
|
|
3077
|
+
targetLoopId: "*",
|
|
3078
|
+
install: (context) => {
|
|
3079
|
+
const registry = getToolRegistry(context);
|
|
3080
|
+
if (!registry) return;
|
|
3081
|
+
const builtinContext = context;
|
|
3082
|
+
const implementation = (arguments_) => options.implementation(arguments_, builtinContext);
|
|
3083
|
+
if (options.effect === void 0) {
|
|
3084
|
+
registry.registerTool(options.toolId, implementation, options.schema);
|
|
3085
|
+
} else {
|
|
3086
|
+
registry.registerTool(
|
|
3087
|
+
options.toolId,
|
|
3088
|
+
implementation,
|
|
3089
|
+
options.schema,
|
|
3090
|
+
options.effect
|
|
3091
|
+
);
|
|
3092
|
+
}
|
|
3093
|
+
registerToolParameterSchema(options.toolId, options.schema, options.metadata);
|
|
3094
|
+
}
|
|
3095
|
+
};
|
|
3096
|
+
}
|
|
3097
|
+
var builtinToolPlugins = [
|
|
3098
|
+
createBuiltinToolPlugin({
|
|
3099
|
+
id: PLUGIN_MCP_CLIENT,
|
|
3100
|
+
toolId: getMcpClientToolId(),
|
|
3101
|
+
schema: mcpClientConfigSchema,
|
|
3102
|
+
metadata: {
|
|
3103
|
+
displayName: "MCP Client",
|
|
3104
|
+
description: "Call a tool on a remote MCP server (transparent proxy). Requires nodeId, serverName, toolName, and optional args."
|
|
3105
|
+
},
|
|
3106
|
+
implementation: mcpClientImpl
|
|
3107
|
+
}),
|
|
3108
|
+
createBuiltinToolPlugin({
|
|
3109
|
+
id: PLUGIN_MCP_FORWARD,
|
|
3110
|
+
toolId: getMcpForwardToolId(),
|
|
3111
|
+
schema: mcpForwardConfigSchema,
|
|
3112
|
+
metadata: {
|
|
3113
|
+
displayName: "MCP Forward",
|
|
3114
|
+
description: "Discover MCP servers and tools on connected nodes. Use action='list' for nodes with servers, action='listTools' for all available tools."
|
|
3115
|
+
},
|
|
3116
|
+
implementation: mcpForwardImpl
|
|
3117
|
+
}),
|
|
3118
|
+
createBuiltinToolPlugin({
|
|
3119
|
+
id: PLUGIN_ORCHESTRATION,
|
|
3120
|
+
toolId: ORCHESTRATION_TOOL_ID,
|
|
3121
|
+
schema: orchestrationConfigSchema,
|
|
3122
|
+
metadata: {
|
|
3123
|
+
displayName: "Orchestration",
|
|
3124
|
+
description: "Discover and manage declarative resources through the policy-scoped orchestration manager."
|
|
3125
|
+
},
|
|
3126
|
+
implementation: orchestrationImpl
|
|
3127
|
+
}),
|
|
3128
|
+
createBuiltinToolPlugin({
|
|
3129
|
+
id: PLUGIN_SPAWN_AGENT,
|
|
3130
|
+
toolId: getSpawnAgentToolId(),
|
|
3131
|
+
schema: spawnAgentConfigSchema,
|
|
3132
|
+
metadata: {
|
|
3133
|
+
displayName: "Spawn Agent",
|
|
3134
|
+
description: "Run a local agent-agent-loop with the given definition and message. Returns summary."
|
|
3135
|
+
},
|
|
3136
|
+
implementation: spawnAgentImpl
|
|
3137
|
+
}),
|
|
3138
|
+
createBuiltinToolPlugin({
|
|
3139
|
+
id: PLUGIN_REMOTE_AGENT,
|
|
3140
|
+
toolId: getRemoteAgentToolId(),
|
|
3141
|
+
schema: remoteAgentConfigSchema,
|
|
3142
|
+
metadata: {
|
|
3143
|
+
displayName: "Remote Agent",
|
|
3144
|
+
description: "Create and run a agent-agent-loop on a remote node. Requires nodeId, definitionId, message. List nodes with no args."
|
|
3145
|
+
},
|
|
3146
|
+
implementation: remoteAgentImpl
|
|
3147
|
+
}),
|
|
3148
|
+
createBuiltinToolPlugin({
|
|
3149
|
+
id: PLUGIN_ASK_QUESTION,
|
|
3150
|
+
toolId: ASK_QUESTION_TOOL_ID,
|
|
3151
|
+
schema: askQuestionConfigSchema,
|
|
3152
|
+
metadata: {
|
|
3153
|
+
displayName: "Ask Question",
|
|
3154
|
+
description: "Block until the user answers (via memeloop.agent.resolveQuestion RPC). Args: question, conversationId, optional timeoutMs."
|
|
3155
|
+
},
|
|
3156
|
+
implementation: askQuestionImpl
|
|
3157
|
+
}),
|
|
3158
|
+
createBuiltinToolPlugin({
|
|
3159
|
+
id: PLUGIN_TODO_WRITE,
|
|
3160
|
+
toolId: TODO_WRITE_TOOL_ID,
|
|
3161
|
+
effect: "update",
|
|
3162
|
+
schema: todoWriteConfigSchema,
|
|
3163
|
+
metadata: {
|
|
3164
|
+
displayName: "Todo Write",
|
|
3165
|
+
description: "Manage structured todo lists: create, update, complete, list, remove. Todos scoped per conversation."
|
|
3166
|
+
},
|
|
3167
|
+
implementation: todoWriteImpl
|
|
3168
|
+
}),
|
|
3169
|
+
createBuiltinToolPlugin({
|
|
3170
|
+
id: PLUGIN_ASK_USER_QUESTION,
|
|
3171
|
+
toolId: ASK_USER_QUESTION_TOOL_ID,
|
|
3172
|
+
schema: askUserQuestionConfigSchema,
|
|
3173
|
+
metadata: {
|
|
3174
|
+
displayName: "Ask User Question",
|
|
3175
|
+
description: "Pause agent and ask user a question. Supports text, single-select, and multi-select input types. Blocks until answered."
|
|
3176
|
+
},
|
|
3177
|
+
implementation: askUserQuestionImpl
|
|
3178
|
+
}),
|
|
3179
|
+
createBuiltinToolPlugin({
|
|
3180
|
+
id: PLUGIN_TASK,
|
|
3181
|
+
toolId: getTaskToolId(),
|
|
3182
|
+
schema: taskToolConfigSchema,
|
|
3183
|
+
metadata: {
|
|
3184
|
+
displayName: "Task Delegation",
|
|
3185
|
+
description: "Delegate a task to a specialized agent-agent-loop (build, plan, explore, oracle, librarian). Supports sync (default) and background modes."
|
|
3186
|
+
},
|
|
3187
|
+
implementation: taskToolImpl
|
|
3188
|
+
})
|
|
3189
|
+
];
|
|
3190
|
+
function getBuiltinToolPlugins() {
|
|
3191
|
+
return builtinToolPlugins;
|
|
3192
|
+
}
|
|
3193
|
+
function registerBuiltinToolPlugins() {
|
|
3194
|
+
const loopRegistry = getLoopRegistry();
|
|
3195
|
+
for (const plugin of builtinToolPlugins) {
|
|
3196
|
+
if (loopRegistry.getPlugin(plugin.id)) continue;
|
|
3197
|
+
loopRegistry.registerPlugin(plugin);
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
// src/promptUtilities/builtinPromptPlugins.ts
|
|
3202
|
+
var FULL_REPLACEMENT_PLUGIN_TOOL_ID = "fullReplacement";
|
|
3203
|
+
var DYNAMIC_POSITION_PLUGIN_TOOL_ID = "dynamicPosition";
|
|
3204
|
+
function registerFullReplacement(reg) {
|
|
3205
|
+
if (reg.has(FULL_REPLACEMENT_PLUGIN_TOOL_ID)) return;
|
|
3206
|
+
reg.set(FULL_REPLACEMENT_PLUGIN_TOOL_ID, (hooks) => {
|
|
3207
|
+
hooks.processPrompts.tapAsync(
|
|
3208
|
+
"fullReplacementLite",
|
|
3209
|
+
(context, callback) => {
|
|
3210
|
+
const msgs = context.messages;
|
|
3211
|
+
if (!Array.isArray(msgs)) {
|
|
3212
|
+
callback();
|
|
3213
|
+
return;
|
|
3214
|
+
}
|
|
3215
|
+
const maxChars = context?.maxReplacementChars ?? 48e3;
|
|
3216
|
+
if (!Number.isFinite(maxChars) || maxChars <= 0) {
|
|
3217
|
+
callback();
|
|
3218
|
+
return;
|
|
3219
|
+
}
|
|
3220
|
+
let total = 0;
|
|
3221
|
+
const kept = [];
|
|
3222
|
+
for (let index = msgs.length - 1; index >= 0; index--) {
|
|
3223
|
+
const m = msgs[index];
|
|
3224
|
+
const c = typeof m?.content === "string" ? m.content : m?.content != null ? JSON.stringify(m.content) : "";
|
|
3225
|
+
total += c.length;
|
|
3226
|
+
if (total > maxChars) break;
|
|
3227
|
+
kept.push(m);
|
|
3228
|
+
}
|
|
3229
|
+
kept.reverse();
|
|
3230
|
+
context.messages = kept;
|
|
3231
|
+
callback();
|
|
3232
|
+
}
|
|
3233
|
+
);
|
|
3234
|
+
});
|
|
3235
|
+
}
|
|
3236
|
+
function registerDynamicPosition(reg) {
|
|
3237
|
+
if (reg.has(DYNAMIC_POSITION_PLUGIN_TOOL_ID)) return;
|
|
3238
|
+
reg.set(DYNAMIC_POSITION_PLUGIN_TOOL_ID, (hooks) => {
|
|
3239
|
+
hooks.processPrompts.tapAsync(
|
|
3240
|
+
"dynamicPositionLite",
|
|
3241
|
+
(context, callback) => {
|
|
3242
|
+
const prompts = context.prompts;
|
|
3243
|
+
const messages = context.messages;
|
|
3244
|
+
if (!Array.isArray(prompts) || prompts.length < 2 || !Array.isArray(messages)) {
|
|
3245
|
+
callback();
|
|
3246
|
+
return;
|
|
3247
|
+
}
|
|
3248
|
+
const userTurns = messages.filter((m) => m?.role === "user").length;
|
|
3249
|
+
if (userTurns < 2) {
|
|
3250
|
+
callback();
|
|
3251
|
+
return;
|
|
3252
|
+
}
|
|
3253
|
+
const deferred = [];
|
|
3254
|
+
const rest = [];
|
|
3255
|
+
for (const n of prompts) {
|
|
3256
|
+
if (n?.dynamicPosition === "deferToEnd") deferred.push(n);
|
|
3257
|
+
else rest.push(n);
|
|
3258
|
+
}
|
|
3259
|
+
if (deferred.length === 0) {
|
|
3260
|
+
callback();
|
|
3261
|
+
return;
|
|
3262
|
+
}
|
|
3263
|
+
context.prompts = [...rest, ...deferred];
|
|
3264
|
+
callback();
|
|
3265
|
+
}
|
|
3266
|
+
);
|
|
3267
|
+
});
|
|
3268
|
+
}
|
|
3269
|
+
function registerBuiltinPromptPlugins(target) {
|
|
3270
|
+
const reg = target ?? getActivePluginRegistry();
|
|
3271
|
+
registerFullReplacement(reg);
|
|
3272
|
+
registerDynamicPosition(reg);
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
// src/runtime.ts
|
|
3276
|
+
async function drainAgentLoop(gen, conversationId, notify) {
|
|
3277
|
+
try {
|
|
3278
|
+
for await (const step of gen) {
|
|
3279
|
+
notify(conversationId, { type: "agent-step", step });
|
|
3280
|
+
}
|
|
3281
|
+
notify(conversationId, { type: "agent-done" });
|
|
3282
|
+
} catch (error) {
|
|
3283
|
+
notify(conversationId, {
|
|
3284
|
+
type: "agent-error",
|
|
3285
|
+
error: error instanceof Error ? error.message : String(error)
|
|
3286
|
+
});
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
function inferDefinitionIdFromConversationId(conversationId) {
|
|
3290
|
+
const parts = conversationId.split(":");
|
|
3291
|
+
if (parts.length >= 2) return parts.slice(0, -1).join(":");
|
|
3292
|
+
return conversationId;
|
|
3293
|
+
}
|
|
3294
|
+
async function resolveDefinitionId(context, conversationId) {
|
|
3295
|
+
try {
|
|
3296
|
+
const meta = await context.storage.getConversationMeta(conversationId);
|
|
3297
|
+
if (meta?.definitionId) return meta.definitionId;
|
|
3298
|
+
} catch {
|
|
3299
|
+
}
|
|
3300
|
+
return inferDefinitionIdFromConversationId(conversationId);
|
|
3301
|
+
}
|
|
3302
|
+
async function resolveLoopProfile(context, definitionId) {
|
|
3303
|
+
const definition = (context.resolveAgentDefinition ? await context.resolveAgentDefinition(definitionId) : null) ?? await context.storage.getAgentDefinition(definitionId) ?? getBuiltinLoopProfile(definitionId) ?? null;
|
|
3304
|
+
if (!definition) return null;
|
|
3305
|
+
return definition;
|
|
3306
|
+
}
|
|
3307
|
+
async function createProfileRunner(context, definitionId, runtime) {
|
|
3308
|
+
const profile = await resolveLoopProfile(context, definitionId);
|
|
3309
|
+
if (!profile) return null;
|
|
3310
|
+
return createAgentProfileRunner(context, profile, runtime);
|
|
3311
|
+
}
|
|
3312
|
+
async function createAgentProfileRunner(context, profile, runtime) {
|
|
3313
|
+
registerBuiltinLoops();
|
|
3314
|
+
registerBuiltinToolPlugins();
|
|
3315
|
+
registerBuiltinPromptPlugins(context.tools.getPromptPlugins?.());
|
|
3316
|
+
const runnerContext = {
|
|
3317
|
+
...context,
|
|
3318
|
+
runtime,
|
|
3319
|
+
scriptPolicy: context.loopScriptPolicy,
|
|
3320
|
+
toolRegistry: context.tools
|
|
3321
|
+
};
|
|
3322
|
+
return getLoopRegistry().createRunnerForProfile(profile, runnerContext);
|
|
3323
|
+
}
|
|
3324
|
+
async function createAgentLoopScriptRunner(context, profile, conversationId) {
|
|
3325
|
+
const cancellation = context.conversationCancellation ?? /* @__PURE__ */ new Set();
|
|
3326
|
+
context.conversationCancellation ??= cancellation;
|
|
3327
|
+
const scriptState = /* @__PURE__ */ new Map();
|
|
3328
|
+
return createAgentProfileRunner(
|
|
3329
|
+
context,
|
|
3330
|
+
profile,
|
|
3331
|
+
createScriptRuntime(context, cancellation, scriptState, conversationId)
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
function createScriptRuntime(context, cancellation, scriptState, conversationId, parentConversationId) {
|
|
3335
|
+
const stateKey = (key) => `${conversationId}:${key}`;
|
|
3336
|
+
return {
|
|
3337
|
+
orchestration: context.orchestration,
|
|
3338
|
+
scriptDeployment: context.scriptDeployment,
|
|
3339
|
+
runChildAgent: async function* (input) {
|
|
3340
|
+
const childRuntime = createScriptRuntime(
|
|
3341
|
+
context,
|
|
3342
|
+
cancellation,
|
|
3343
|
+
scriptState,
|
|
3344
|
+
input.conversationId,
|
|
3345
|
+
conversationId
|
|
3346
|
+
);
|
|
3347
|
+
const run = await createProfileRunner(context, input.profileId, childRuntime);
|
|
3348
|
+
if (!run) {
|
|
3349
|
+
yield {
|
|
3350
|
+
type: "message",
|
|
3351
|
+
data: `Child agent profile not found: ${input.profileId}`
|
|
3352
|
+
};
|
|
3353
|
+
return;
|
|
3354
|
+
}
|
|
3355
|
+
yield* run({ conversationId: input.conversationId, message: input.prompt });
|
|
3356
|
+
},
|
|
3357
|
+
log: (event, data) => context.logger?.debug?.(event, data),
|
|
3358
|
+
emit: () => void 0,
|
|
3359
|
+
signal: {
|
|
3360
|
+
get cancelled() {
|
|
3361
|
+
return cancellation.has(conversationId) || (parentConversationId ? cancellation.has(parentConversationId) : false);
|
|
3362
|
+
}
|
|
3363
|
+
},
|
|
3364
|
+
state: {
|
|
3365
|
+
get: async (key) => {
|
|
3366
|
+
const local = scriptState.get(stateKey(key));
|
|
3367
|
+
if (local !== void 0) return local;
|
|
3368
|
+
const persisted = await context.loopCheckpoints?.loadCheckpoint(conversationId, `state:${key}`);
|
|
3369
|
+
if (persisted !== void 0) scriptState.set(stateKey(key), persisted);
|
|
3370
|
+
return persisted;
|
|
3371
|
+
},
|
|
3372
|
+
set: async (key, value) => {
|
|
3373
|
+
scriptState.set(stateKey(key), value);
|
|
3374
|
+
await context.loopCheckpoints?.saveCheckpoint(conversationId, `state:${key}`, value);
|
|
3375
|
+
},
|
|
3376
|
+
update: async (key, updater) => {
|
|
3377
|
+
const fullKey = stateKey(key);
|
|
3378
|
+
const previous = scriptState.get(fullKey);
|
|
3379
|
+
const next = updater(previous);
|
|
3380
|
+
scriptState.set(fullKey, next);
|
|
3381
|
+
await context.loopCheckpoints?.saveCheckpoint(conversationId, `state:${key}`, next);
|
|
3382
|
+
}
|
|
3383
|
+
},
|
|
3384
|
+
checkpoint: async (key, result) => {
|
|
3385
|
+
scriptState.set(stateKey(`checkpoint:${key}`), result);
|
|
3386
|
+
await context.loopCheckpoints?.saveCheckpoint(conversationId, key, result);
|
|
3387
|
+
},
|
|
3388
|
+
loadCheckpoint: async (key) => {
|
|
3389
|
+
const memoryKey = stateKey(`checkpoint:${key}`);
|
|
3390
|
+
if (scriptState.has(memoryKey)) return scriptState.get(memoryKey);
|
|
3391
|
+
const result = await context.loopCheckpoints?.loadCheckpoint(conversationId, key);
|
|
3392
|
+
if (result !== void 0) scriptState.set(memoryKey, result);
|
|
3393
|
+
return result;
|
|
3394
|
+
}
|
|
3395
|
+
};
|
|
3396
|
+
}
|
|
3397
|
+
async function createAgentLoopRunner(context, options) {
|
|
3398
|
+
const cancellation = context.conversationCancellation ?? /* @__PURE__ */ new Set();
|
|
3399
|
+
context.conversationCancellation ??= cancellation;
|
|
3400
|
+
const scriptState = /* @__PURE__ */ new Map();
|
|
3401
|
+
const conversationId = options.conversationId ?? options.definitionId;
|
|
3402
|
+
return createProfileRunner(
|
|
3403
|
+
context,
|
|
3404
|
+
options.definitionId,
|
|
3405
|
+
createScriptRuntime(context, cancellation, scriptState, conversationId)
|
|
3406
|
+
);
|
|
3407
|
+
}
|
|
3408
|
+
function createMemeLoopRuntime(context) {
|
|
3409
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
3410
|
+
const cancellation = context.conversationCancellation ?? /* @__PURE__ */ new Set();
|
|
3411
|
+
const scriptState = /* @__PURE__ */ new Map();
|
|
3412
|
+
context.conversationCancellation ??= cancellation;
|
|
3413
|
+
function notify(conversationId, update) {
|
|
3414
|
+
const set = listeners.get(conversationId);
|
|
3415
|
+
if (!set) return;
|
|
3416
|
+
for (const listener of set) {
|
|
3417
|
+
listener(update);
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
async function runAgentLoop(input, definitionId) {
|
|
3421
|
+
const run = context.runAgentToolLoop ?? await createProfileRunner(
|
|
3422
|
+
context,
|
|
3423
|
+
definitionId,
|
|
3424
|
+
createScriptRuntime(context, cancellation, scriptState, input.conversationId)
|
|
3425
|
+
);
|
|
3426
|
+
if (!run) return false;
|
|
3427
|
+
void drainAgentLoop(run(input), input.conversationId, notify);
|
|
3428
|
+
return true;
|
|
3429
|
+
}
|
|
3430
|
+
async function* runChildAgent(input) {
|
|
3431
|
+
const run = await createProfileRunner(
|
|
3432
|
+
context,
|
|
3433
|
+
input.profileId,
|
|
3434
|
+
createScriptRuntime(context, cancellation, scriptState, input.conversationId)
|
|
3435
|
+
);
|
|
3436
|
+
if (!run) {
|
|
3437
|
+
yield {
|
|
3438
|
+
type: "message",
|
|
3439
|
+
data: `Child agent profile not found: ${input.profileId}`
|
|
3440
|
+
};
|
|
3441
|
+
return;
|
|
3442
|
+
}
|
|
3443
|
+
yield* run({ conversationId: input.conversationId, message: input.prompt });
|
|
3444
|
+
}
|
|
3445
|
+
context.runChildAgent ??= runChildAgent;
|
|
3446
|
+
return {
|
|
3447
|
+
async createAgent(options) {
|
|
3448
|
+
const now = Date.now();
|
|
3449
|
+
const conversationId = `${options.definitionId}:${now.toString(36)}`;
|
|
3450
|
+
cancellation?.delete(conversationId);
|
|
3451
|
+
const meta = {
|
|
3452
|
+
conversationId,
|
|
3453
|
+
title: options.definitionId,
|
|
3454
|
+
lastMessagePreview: context.runAgentToolLoop ? "" : options.initialMessage ?? "",
|
|
3455
|
+
lastMessageTimestamp: now,
|
|
3456
|
+
messageCount: context.runAgentToolLoop || !options.initialMessage ? 0 : 1,
|
|
3457
|
+
originNodeId: "local",
|
|
3458
|
+
definitionId: options.definitionId,
|
|
3459
|
+
isUserInitiated: true
|
|
3460
|
+
};
|
|
3461
|
+
await context.storage.upsertConversationMetadata(meta);
|
|
3462
|
+
if (options.initialMessage) {
|
|
3463
|
+
const started = await runAgentLoop(
|
|
3464
|
+
{ conversationId, message: options.initialMessage },
|
|
3465
|
+
options.definitionId
|
|
3466
|
+
);
|
|
3467
|
+
if (started) {
|
|
3468
|
+
notify(conversationId, { type: "created", conversationId });
|
|
3469
|
+
return { conversationId };
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
if (options.initialMessage) {
|
|
3473
|
+
const message = {
|
|
3474
|
+
messageId: `${conversationId}:m1`,
|
|
3475
|
+
conversationId,
|
|
3476
|
+
originNodeId: meta.originNodeId,
|
|
3477
|
+
timestamp: now,
|
|
3478
|
+
lamportClock: 1,
|
|
3479
|
+
role: "user",
|
|
3480
|
+
content: options.initialMessage
|
|
3481
|
+
};
|
|
3482
|
+
await context.storage.appendMessage(message);
|
|
3483
|
+
}
|
|
3484
|
+
notify(conversationId, { type: "created", conversationId });
|
|
3485
|
+
return { conversationId };
|
|
3486
|
+
},
|
|
3487
|
+
async sendMessage(options) {
|
|
3488
|
+
cancellation?.delete(options.conversationId);
|
|
3489
|
+
const definitionId = options.definitionId ?? await resolveDefinitionId(context, options.conversationId);
|
|
3490
|
+
const started = await runAgentLoop(
|
|
3491
|
+
{
|
|
3492
|
+
conversationId: options.conversationId,
|
|
3493
|
+
message: options.message,
|
|
3494
|
+
userMessage: options.userMessage,
|
|
3495
|
+
resumeSession: options.resumeSession
|
|
3496
|
+
},
|
|
3497
|
+
definitionId
|
|
3498
|
+
);
|
|
3499
|
+
if (started) {
|
|
3500
|
+
notify(options.conversationId, { type: "message-queued" });
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
if (options.resumeSession && options.resumeSession.length > 0) {
|
|
3504
|
+
await context.storage.insertMessagesIfAbsent(options.resumeSession);
|
|
3505
|
+
}
|
|
3506
|
+
const now = Date.now();
|
|
3507
|
+
const lamportClock = await nextLamportClockForConversation(
|
|
3508
|
+
context.storage,
|
|
3509
|
+
options.conversationId
|
|
3510
|
+
);
|
|
3511
|
+
const hostUserMessage = options.userMessage;
|
|
3512
|
+
const message = {
|
|
3513
|
+
...hostUserMessage,
|
|
3514
|
+
messageId: hostUserMessage?.messageId ?? `${options.conversationId}:${now.toString(36)}`,
|
|
3515
|
+
conversationId: options.conversationId,
|
|
3516
|
+
originNodeId: hostUserMessage?.originNodeId ?? "local",
|
|
3517
|
+
timestamp: hostUserMessage?.timestamp ?? now,
|
|
3518
|
+
lamportClock: hostUserMessage?.lamportClock ?? lamportClock,
|
|
3519
|
+
role: "user",
|
|
3520
|
+
content: hostUserMessage?.content ?? options.message
|
|
3521
|
+
};
|
|
3522
|
+
await context.storage.appendMessage(message);
|
|
3523
|
+
notify(options.conversationId, { type: "message-queued" });
|
|
3524
|
+
},
|
|
3525
|
+
async cancelAgent(conversationId) {
|
|
3526
|
+
cancellation?.add(conversationId);
|
|
3527
|
+
notify(conversationId, { type: "cancelled" });
|
|
3528
|
+
},
|
|
3529
|
+
subscribeToUpdates(conversationId, listener) {
|
|
3530
|
+
const set = listeners.get(conversationId) ?? /* @__PURE__ */ new Set();
|
|
3531
|
+
set.add(listener);
|
|
3532
|
+
listeners.set(conversationId, set);
|
|
3533
|
+
return () => {
|
|
3534
|
+
const current = listeners.get(conversationId);
|
|
3535
|
+
if (!current) return;
|
|
3536
|
+
current.delete(listener);
|
|
3537
|
+
if (current.size === 0) {
|
|
3538
|
+
listeners.delete(conversationId);
|
|
3539
|
+
}
|
|
3540
|
+
};
|
|
3541
|
+
}
|
|
3542
|
+
};
|
|
3543
|
+
}
|
|
3544
|
+
|
|
3545
|
+
export {
|
|
3546
|
+
BUILTIN_AGENT_AGENT_LOOP_ARTIFACT_RESOURCE_LIFECYCLE_SCRIPT_ID,
|
|
3547
|
+
BUILTIN_AGENT_AGENT_LOOP_DECLARATIVE_AGENT_RUN_SCRIPT_ID,
|
|
3548
|
+
BUILTIN_AGENT_AGENT_LOOP_QUALITY_GATE_SCRIPT_ID,
|
|
3549
|
+
builtinAgentAgentLoopSources,
|
|
3550
|
+
getBuiltinAgentAgentLoopSource,
|
|
3551
|
+
waitForCondition,
|
|
3552
|
+
createAgentClient,
|
|
3553
|
+
toolSchemaToJsonSchema,
|
|
3554
|
+
registerToolParameterSchema,
|
|
3555
|
+
getToolParameterSchema,
|
|
3556
|
+
getToolMetadata,
|
|
3557
|
+
BUILTIN_RUNTIME_CLASSES,
|
|
3558
|
+
selectRuntimeClass,
|
|
3559
|
+
BUILTIN_AGENT_TOOL_LOOP_DEFAULT_SCRIPT_ID,
|
|
3560
|
+
builtinAgentToolLoopSources,
|
|
3561
|
+
getBuiltinAgentToolLoopSource,
|
|
3562
|
+
digestNormalizedScript,
|
|
3563
|
+
validateScript,
|
|
3564
|
+
normalizeScript,
|
|
3565
|
+
loadAgentToolLoopScript,
|
|
3566
|
+
createAgentToolLoopDefinition,
|
|
3567
|
+
AGENT_TOOL_LOOP_ID,
|
|
3568
|
+
AGENT_AGENT_LOOP_ID,
|
|
3569
|
+
registerBuiltinLoops,
|
|
3570
|
+
resolveQuestionAnswer,
|
|
3571
|
+
askQuestionConfigSchema,
|
|
3572
|
+
ASK_QUESTION_TOOL_ID,
|
|
3573
|
+
askQuestionImpl,
|
|
3574
|
+
askUserQuestionConfigSchema,
|
|
3575
|
+
ASK_USER_QUESTION_TOOL_ID,
|
|
3576
|
+
askUserQuestionImpl,
|
|
3577
|
+
mcpClientConfigSchema,
|
|
3578
|
+
mcpClientImpl,
|
|
3579
|
+
getMcpClientToolId,
|
|
3580
|
+
mcpForwardConfigSchema,
|
|
3581
|
+
mcpForwardImpl,
|
|
3582
|
+
getMcpForwardToolId,
|
|
3583
|
+
ORCHESTRATION_TOOL_ID,
|
|
3584
|
+
orchestrationConfigSchema,
|
|
3585
|
+
orchestrationImpl,
|
|
3586
|
+
remoteAgentConfigSchema,
|
|
3587
|
+
remoteAgentListImpl,
|
|
3588
|
+
remoteAgentImpl,
|
|
3589
|
+
getRemoteAgentToolId,
|
|
3590
|
+
spawnAgentConfigSchema,
|
|
3591
|
+
spawnAgentImpl,
|
|
3592
|
+
getSpawnAgentToolId,
|
|
3593
|
+
buildAgent,
|
|
3594
|
+
planAgent,
|
|
3595
|
+
exploreAgent,
|
|
3596
|
+
oracleAgent,
|
|
3597
|
+
librarianAgent,
|
|
3598
|
+
BUILTIN_AGENT_PROFILES,
|
|
3599
|
+
AgentProfileRegistry,
|
|
3600
|
+
getAgentProfileRegistry,
|
|
3601
|
+
resetAgentProfileRegistry,
|
|
3602
|
+
taskToolConfigSchema,
|
|
3603
|
+
taskToolImpl,
|
|
3604
|
+
getTaskToolId,
|
|
3605
|
+
todoWriteConfigSchema,
|
|
3606
|
+
TODO_WRITE_TOOL_ID,
|
|
3607
|
+
__clearTodoStore,
|
|
3608
|
+
todoWriteImpl,
|
|
3609
|
+
PLUGIN_MCP_CLIENT,
|
|
3610
|
+
PLUGIN_MCP_FORWARD,
|
|
3611
|
+
PLUGIN_ORCHESTRATION,
|
|
3612
|
+
PLUGIN_SPAWN_AGENT,
|
|
3613
|
+
PLUGIN_REMOTE_AGENT,
|
|
3614
|
+
PLUGIN_ASK_QUESTION,
|
|
3615
|
+
PLUGIN_TODO_WRITE,
|
|
3616
|
+
PLUGIN_ASK_USER_QUESTION,
|
|
3617
|
+
PLUGIN_TASK,
|
|
3618
|
+
BUILTIN_TOOL_PLUGIN_IDS,
|
|
3619
|
+
getBuiltinToolPlugins,
|
|
3620
|
+
registerBuiltinToolPlugins,
|
|
3621
|
+
registerBuiltinPromptPlugins,
|
|
3622
|
+
createAgentProfileRunner,
|
|
3623
|
+
createAgentLoopScriptRunner,
|
|
3624
|
+
createAgentLoopRunner,
|
|
3625
|
+
createMemeLoopRuntime,
|
|
3626
|
+
defaultRequestedInterfacesForTrustClass,
|
|
3627
|
+
maxScriptBytesForTrustClass,
|
|
3628
|
+
admitScript,
|
|
3629
|
+
remoteDeploymentToWorkloadManifest,
|
|
3630
|
+
deployGeneratedScript,
|
|
3631
|
+
createScriptLoadGate,
|
|
3632
|
+
createScriptDeploymentClient,
|
|
3633
|
+
loadAgentAgentLoopScript,
|
|
3634
|
+
createAgentAgentLoopDefinition,
|
|
3635
|
+
getAgentAgentLoopId
|
|
3636
|
+
};
|
|
3637
|
+
//# sourceMappingURL=chunk-XHRBV6I3.js.map
|