@norskvideo/norsk-studio-alpha 1.27.0-2026-01-25-4ad2ca43 → 1.27.0-2026-01-31-e37a5429
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/client/info.js +1630 -1316
- package/client/style.css +7 -599
- package/lib/info.js +6 -4
- package/lib/info.js.map +1 -1
- package/lib/processor.objectDetect/_gen/schema.d.ts +12 -0
- package/lib/processor.objectDetect/_gen/schema.js +16 -0
- package/lib/processor.objectDetect/_gen/schema.js.map +1 -0
- package/lib/processor.objectDetect/_gen/types.d.ts +49 -0
- package/lib/processor.objectDetect/_gen/types.js.map +1 -0
- package/lib/processor.objectDetect/_gen/zod.js +60 -0
- package/lib/processor.objectDetect/_gen/zod.js.map +1 -0
- package/lib/processor.objectDetect/info.d.ts +27 -0
- package/lib/processor.objectDetect/info.js +63 -0
- package/lib/processor.objectDetect/info.js.map +1 -0
- package/lib/processor.objectDetect/inline-view.d.ts +6 -0
- package/lib/processor.objectDetect/inline-view.js +41 -0
- package/lib/processor.objectDetect/inline-view.js.map +1 -0
- package/lib/processor.objectDetect/runtime.d.ts +28 -0
- package/lib/processor.objectDetect/runtime.js +112 -0
- package/lib/processor.objectDetect/runtime.js.map +1 -0
- package/lib/processor.objectDetect/types.yaml +78 -0
- package/lib/test/output.tams.js.map +1 -1
- package/lib/util.claudeAgent/_gen/schema.d.ts +17 -0
- package/lib/util.claudeAgent/_gen/schema.js +21 -0
- package/lib/util.claudeAgent/_gen/schema.js.map +1 -0
- package/lib/util.claudeAgent/_gen/types.d.ts +370 -0
- package/lib/util.claudeAgent/_gen/types.js.map +1 -0
- package/lib/util.claudeAgent/_gen/zod.js +147 -0
- package/lib/util.claudeAgent/_gen/zod.js.map +1 -0
- package/lib/util.claudeAgent/info.d.ts +63 -0
- package/lib/util.claudeAgent/info.js +131 -0
- package/lib/util.claudeAgent/info.js.map +1 -0
- package/lib/util.claudeAgent/runtime.d.ts +105 -0
- package/lib/util.claudeAgent/runtime.js +567 -0
- package/lib/util.claudeAgent/runtime.js.map +1 -0
- package/lib/util.claudeAgent/types.yaml +393 -0
- package/lib/util.geminiAgent/_gen/schema.d.ts +17 -0
- package/lib/util.geminiAgent/_gen/schema.js +21 -0
- package/lib/util.geminiAgent/_gen/schema.js.map +1 -0
- package/lib/util.geminiAgent/_gen/types.d.ts +370 -0
- package/lib/util.geminiAgent/_gen/types.js.map +1 -0
- package/lib/util.geminiAgent/_gen/zod.d.ts +2 -0
- package/lib/util.geminiAgent/_gen/zod.js +147 -0
- package/lib/util.geminiAgent/_gen/zod.js.map +1 -0
- package/lib/util.geminiAgent/info.d.ts +63 -0
- package/lib/util.geminiAgent/info.js +131 -0
- package/lib/util.geminiAgent/info.js.map +1 -0
- package/lib/util.geminiAgent/runtime.d.ts +107 -0
- package/lib/util.geminiAgent/runtime.js +621 -0
- package/lib/util.geminiAgent/runtime.js.map +1 -0
- package/lib/util.geminiAgent/types.yaml +392 -0
- package/package.json +24 -5
- package/client/util.aiChat/styles.css +0 -371
- package/lib/util.agent/_gen/schema.d.ts +0 -13
- package/lib/util.agent/_gen/schema.js +0 -17
- package/lib/util.agent/_gen/schema.js.map +0 -1
- package/lib/util.agent/_gen/types.d.ts +0 -343
- package/lib/util.agent/_gen/types.js.map +0 -1
- package/lib/util.agent/_gen/zod.js +0 -206
- package/lib/util.agent/_gen/zod.js.map +0 -1
- package/lib/util.agent/fullscreen-view.d.ts +0 -4
- package/lib/util.agent/fullscreen-view.js +0 -142
- package/lib/util.agent/fullscreen-view.js.map +0 -1
- package/lib/util.agent/info.d.ts +0 -126
- package/lib/util.agent/info.js +0 -141
- package/lib/util.agent/info.js.map +0 -1
- package/lib/util.agent/inline-view.d.ts +0 -6
- package/lib/util.agent/inline-view.js +0 -43
- package/lib/util.agent/inline-view.js.map +0 -1
- package/lib/util.agent/runtime.d.ts +0 -180
- package/lib/util.agent/runtime.js +0 -1254
- package/lib/util.agent/runtime.js.map +0 -1
- package/lib/util.agent/summary-view.d.ts +0 -4
- package/lib/util.agent/summary-view.js +0 -68
- package/lib/util.agent/summary-view.js.map +0 -1
- package/lib/util.agent/types.d.ts +0 -285
- package/lib/util.agent/types.js.map +0 -1
- package/lib/util.agent/types.yaml +0 -440
- package/lib/util.aiChat/_gen/schema.d.ts +0 -12
- package/lib/util.aiChat/_gen/schema.js +0 -16
- package/lib/util.aiChat/_gen/schema.js.map +0 -1
- package/lib/util.aiChat/_gen/types.d.ts +0 -98
- package/lib/util.aiChat/_gen/types.js.map +0 -1
- package/lib/util.aiChat/_gen/zod.js +0 -132
- package/lib/util.aiChat/_gen/zod.js.map +0 -1
- package/lib/util.aiChat/info.d.ts +0 -70
- package/lib/util.aiChat/info.js +0 -92
- package/lib/util.aiChat/info.js.map +0 -1
- package/lib/util.aiChat/runtime.d.ts +0 -32
- package/lib/util.aiChat/runtime.js +0 -304
- package/lib/util.aiChat/runtime.js.map +0 -1
- package/lib/util.aiChat/summary-view.d.ts +0 -7
- package/lib/util.aiChat/summary-view.js +0 -48
- package/lib/util.aiChat/summary-view.js.map +0 -1
- package/lib/util.aiChat/types.d.ts +0 -62
- package/lib/util.aiChat/types.js +0 -3
- package/lib/util.aiChat/types.js.map +0 -1
- package/lib/util.aiChat/types.yaml +0 -148
- /package/lib/{util.agent → processor.objectDetect}/_gen/types.js +0 -0
- /package/lib/{util.agent → processor.objectDetect}/_gen/zod.d.ts +0 -0
- /package/lib/{util.agent → util.claudeAgent/_gen}/types.js +0 -0
- /package/lib/{util.aiChat → util.claudeAgent}/_gen/zod.d.ts +0 -0
- /package/lib/{util.aiChat → util.geminiAgent}/_gen/types.js +0 -0
|
@@ -1,1254 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const base_nodes_1 = require("@norskvideo/norsk-studio/lib/extension/base-nodes");
|
|
7
|
-
const api_1 = require("@norskvideo/norsk-studio/lib/server/api");
|
|
8
|
-
const api_validation_1 = require("@norskvideo/norsk-studio/lib/server/api-validation");
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const runtime_types_1 = require("@norskvideo/norsk-studio/lib/extension/runtime-types");
|
|
11
|
-
const logging_1 = require("@norskvideo/norsk-studio/lib/server/logging");
|
|
12
|
-
class AgentDefinition {
|
|
13
|
-
async schemas() {
|
|
14
|
-
return (0, runtime_types_1.schemaFromTypes)(path_1.default.join(__dirname, 'types.yaml'), {
|
|
15
|
-
config: 'AgentSettings',
|
|
16
|
-
state: 'AgentState'
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
async instanceRoutes() {
|
|
20
|
-
return (0, api_1.defineJsonApi)(path_1.default.join(__dirname, 'types.yaml'), {
|
|
21
|
-
'/memory/working': {
|
|
22
|
-
get: ({ node }) => ({
|
|
23
|
-
swt: api_validation_1.NoBody,
|
|
24
|
-
handler: async () => {
|
|
25
|
-
const result = await node.handleHttpRequest('/memory/working', 'GET');
|
|
26
|
-
return { statusCode: 200, body: result };
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
},
|
|
30
|
-
'/memory/persistent': {
|
|
31
|
-
get: ({ node }) => ({
|
|
32
|
-
swt: api_validation_1.NoBody,
|
|
33
|
-
handler: async () => {
|
|
34
|
-
const result = await node.handleHttpRequest('/memory/persistent', 'GET');
|
|
35
|
-
return { statusCode: 200, body: result };
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
},
|
|
39
|
-
'/memory/summary': {
|
|
40
|
-
get: ({ node }) => ({
|
|
41
|
-
swt: api_validation_1.NoBody,
|
|
42
|
-
handler: async () => {
|
|
43
|
-
const result = await node.handleHttpRequest('/memory/summary', 'GET');
|
|
44
|
-
return { statusCode: 200, body: result };
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
},
|
|
48
|
-
'/status/detailed': {
|
|
49
|
-
get: ({ node }) => ({
|
|
50
|
-
swt: api_validation_1.NoBody,
|
|
51
|
-
handler: async () => {
|
|
52
|
-
const result = await node.handleHttpRequest('/status/detailed', 'GET');
|
|
53
|
-
return { statusCode: 200, body: result };
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
async create(_norsk, cfg, cb, runtime) {
|
|
60
|
-
const node = new Agent(cfg, runtime);
|
|
61
|
-
cb(node);
|
|
62
|
-
}
|
|
63
|
-
handleCommand(node, command) {
|
|
64
|
-
const commandType = command.type;
|
|
65
|
-
switch (commandType) {
|
|
66
|
-
case "start_agent": {
|
|
67
|
-
void node.start();
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case "stop_agent": {
|
|
71
|
-
node.stop();
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
case "pause_agent": {
|
|
75
|
-
node.pause();
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
case "resume_agent": {
|
|
79
|
-
node.resume();
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
case "assign_task": {
|
|
83
|
-
break;
|
|
84
|
-
}
|
|
85
|
-
case "cancel_task": {
|
|
86
|
-
break;
|
|
87
|
-
}
|
|
88
|
-
case "update_goal": {
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
default: {
|
|
92
|
-
const _exhaustive = commandType;
|
|
93
|
-
throw new Error(`Unhandled command type: ${String(_exhaustive)}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
exports.default = AgentDefinition;
|
|
99
|
-
class Agent extends base_nodes_1.CustomAutoDuplexNode {
|
|
100
|
-
config;
|
|
101
|
-
runtime;
|
|
102
|
-
isRunning = false;
|
|
103
|
-
isPaused = false;
|
|
104
|
-
cycleResetTimer;
|
|
105
|
-
cyclesThisMinute = 0;
|
|
106
|
-
totalCycles = 0;
|
|
107
|
-
memory;
|
|
108
|
-
initialized = false;
|
|
109
|
-
timerQueue = [];
|
|
110
|
-
initializationHistory = [];
|
|
111
|
-
isExecutingCycle = false;
|
|
112
|
-
activeTimers = new Map();
|
|
113
|
-
immediateSubscriptions = new Map();
|
|
114
|
-
aggregatedSubscriptions = new Map();
|
|
115
|
-
getAvailableTools() {
|
|
116
|
-
return [
|
|
117
|
-
{
|
|
118
|
-
name: 'studio_agent_setTimer',
|
|
119
|
-
description: 'Set a timer that triggers after specified seconds',
|
|
120
|
-
inputSchema: {
|
|
121
|
-
type: 'object',
|
|
122
|
-
properties: {
|
|
123
|
-
timerId: { type: 'string', description: 'Unique ID for this timer' },
|
|
124
|
-
delaySeconds: { type: 'number', description: 'How many seconds until timer fires' },
|
|
125
|
-
cyclePrompt: { type: 'string', description: 'The detailed prompt for the LLM when this timer fires' },
|
|
126
|
-
recurring: { type: 'boolean', description: 'If true, timer repeats every delaySeconds' }
|
|
127
|
-
},
|
|
128
|
-
required: ['timerId', 'delaySeconds', 'cyclePrompt']
|
|
129
|
-
},
|
|
130
|
-
execute: async (args) => {
|
|
131
|
-
return await this.handleAgentTool('studio_agent_setTimer', args);
|
|
132
|
-
}
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: 'studio_agent_cancelTimer',
|
|
136
|
-
description: 'Cancel an active timer',
|
|
137
|
-
inputSchema: {
|
|
138
|
-
type: 'object',
|
|
139
|
-
properties: {
|
|
140
|
-
timerId: { type: 'string', description: 'ID of timer to cancel' }
|
|
141
|
-
},
|
|
142
|
-
required: ['timerId']
|
|
143
|
-
},
|
|
144
|
-
execute: async (args) => {
|
|
145
|
-
return await this.handleAgentTool('studio_agent_cancelTimer', args);
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
name: 'studio_agent_subscribeImmediate',
|
|
150
|
-
description: 'Subscribe to events that need immediate action',
|
|
151
|
-
inputSchema: {
|
|
152
|
-
type: 'object',
|
|
153
|
-
properties: {
|
|
154
|
-
componentId: { type: 'string', description: 'ID of component to subscribe to' },
|
|
155
|
-
eventType: { type: 'string', description: 'Type of event from listEvents' },
|
|
156
|
-
cyclePrompt: { type: 'string', description: 'The detailed prompt for the LLM when this event occurs' }
|
|
157
|
-
},
|
|
158
|
-
required: ['componentId', 'eventType', 'cyclePrompt']
|
|
159
|
-
},
|
|
160
|
-
execute: async (args) => {
|
|
161
|
-
return await this.handleAgentTool('studio_agent_subscribeImmediate', args);
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
name: 'studio_agent_subscribeAggregated',
|
|
166
|
-
description: 'Subscribe to high-frequency events for batch analysis',
|
|
167
|
-
inputSchema: {
|
|
168
|
-
type: 'object',
|
|
169
|
-
properties: {
|
|
170
|
-
subscriptionId: { type: 'string', description: 'Unique ID for this subscription group' },
|
|
171
|
-
sources: {
|
|
172
|
-
type: 'array',
|
|
173
|
-
items: {
|
|
174
|
-
type: 'object',
|
|
175
|
-
properties: {
|
|
176
|
-
componentId: { type: 'string' },
|
|
177
|
-
eventType: { type: 'string' },
|
|
178
|
-
fieldPath: { type: 'string', description: 'Optional dot notation path to extract specific field (e.g., "levels.rms" for audio levels)' }
|
|
179
|
-
},
|
|
180
|
-
required: ['componentId', 'eventType']
|
|
181
|
-
},
|
|
182
|
-
description: 'Events to aggregate, with optional field extraction to reduce context bloat'
|
|
183
|
-
},
|
|
184
|
-
windowSeconds: { type: 'number', description: 'How often to analyze, e.g., 10' },
|
|
185
|
-
retentionSeconds: { type: 'number', description: 'How much history to keep, defaults to window' },
|
|
186
|
-
cyclePrompt: { type: 'string', description: 'The detailed prompt for the LLM when analyzing aggregated data' }
|
|
187
|
-
},
|
|
188
|
-
required: ['subscriptionId', 'sources', 'windowSeconds', 'cyclePrompt']
|
|
189
|
-
},
|
|
190
|
-
execute: async (args) => {
|
|
191
|
-
return await this.handleAgentTool('studio_agent_subscribeAggregated', args);
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
name: 'studio_agent_unsubscribe',
|
|
196
|
-
description: 'Remove an event subscription',
|
|
197
|
-
inputSchema: {
|
|
198
|
-
type: 'object',
|
|
199
|
-
properties: {
|
|
200
|
-
subscriptionId: { type: 'string', description: 'ID to unsubscribe' }
|
|
201
|
-
},
|
|
202
|
-
required: ['subscriptionId']
|
|
203
|
-
},
|
|
204
|
-
execute: async (args) => {
|
|
205
|
-
return await this.handleAgentTool('studio_agent_unsubscribe', args);
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
name: 'studio_agent_listSubscriptions',
|
|
210
|
-
description: 'List all active subscriptions and timers',
|
|
211
|
-
inputSchema: {
|
|
212
|
-
type: 'object',
|
|
213
|
-
properties: {},
|
|
214
|
-
required: []
|
|
215
|
-
},
|
|
216
|
-
execute: async (args) => {
|
|
217
|
-
return await this.handleAgentTool('studio_agent_listSubscriptions', args);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
];
|
|
221
|
-
}
|
|
222
|
-
constructor(config, runtime) {
|
|
223
|
-
super(config.id);
|
|
224
|
-
console.log("AGENT CONSTRUCTOR called - id:", config.id, "goal:", config.goal);
|
|
225
|
-
this.config = config;
|
|
226
|
-
this.runtime = runtime;
|
|
227
|
-
this.cycleResetTimer = setInterval(() => {
|
|
228
|
-
if (this.cyclesThisMinute == 0)
|
|
229
|
-
return;
|
|
230
|
-
this.cyclesThisMinute = 0;
|
|
231
|
-
this.runtime.updates.raiseEvent({
|
|
232
|
-
type: 'action_taken',
|
|
233
|
-
action: {
|
|
234
|
-
id: `cycle-reset-${Date.now()}`,
|
|
235
|
-
type: 'analysis',
|
|
236
|
-
timestamp: new Date().toISOString(),
|
|
237
|
-
description: 'Reset cycle counter',
|
|
238
|
-
parameters: {
|
|
239
|
-
cyclesThisMinute: this.cyclesThisMinute,
|
|
240
|
-
totalCycles: this.cyclesThisMinute,
|
|
241
|
-
actionType: 'cycle_reset'
|
|
242
|
-
},
|
|
243
|
-
success: true
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
}, 60000);
|
|
247
|
-
setTimeout(() => {
|
|
248
|
-
void this.start();
|
|
249
|
-
}, 1000);
|
|
250
|
-
}
|
|
251
|
-
async start() {
|
|
252
|
-
console.log("AGENT START called - isRunning:", this.isRunning);
|
|
253
|
-
if (this.isRunning) {
|
|
254
|
-
console.log("AGENT already running, returning early");
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
console.log("AGENT starting up...");
|
|
258
|
-
this.isRunning = true;
|
|
259
|
-
this.isPaused = false;
|
|
260
|
-
this.isExecutingCycle = true;
|
|
261
|
-
console.log("AGENT calling initialize()");
|
|
262
|
-
await this.initialize();
|
|
263
|
-
console.log("AGENT initialize() completed, initialized =", this.initialized);
|
|
264
|
-
this.isExecutingCycle = false;
|
|
265
|
-
console.log("AGENT set isExecutingCycle = false, checking timer queue");
|
|
266
|
-
if (this.timerQueue.length > 0) {
|
|
267
|
-
console.log("AGENT has", this.timerQueue.length, "timers in queue, processing...");
|
|
268
|
-
void this.processTimerQueue();
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
console.log("AGENT timer queue is empty");
|
|
272
|
-
}
|
|
273
|
-
this.runtime.updates.raiseEvent({
|
|
274
|
-
type: 'agent_started',
|
|
275
|
-
timestamp: new Date().toISOString()
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
async initialize() {
|
|
279
|
-
console.log("AGENT INITIALIZING - componentId:", this.config.id, "goal:", this.config.goal);
|
|
280
|
-
(0, logging_1.debuglog)("Agent initialization starting", {
|
|
281
|
-
componentId: this.config.id,
|
|
282
|
-
goal: this.config.goal,
|
|
283
|
-
systemPrompt: this.config.systemPrompt.substring(0, 100) + '...',
|
|
284
|
-
maxCyclesPerMinute: this.config.maxCyclesPerMinute
|
|
285
|
-
});
|
|
286
|
-
this.runtime.updates.raiseEvent({
|
|
287
|
-
type: 'action_taken',
|
|
288
|
-
action: {
|
|
289
|
-
id: `init-cycle-${Date.now()}`,
|
|
290
|
-
type: 'analysis',
|
|
291
|
-
timestamp: new Date().toISOString(),
|
|
292
|
-
description: `Initialization cycle ${this.cyclesThisMinute}`,
|
|
293
|
-
parameters: {
|
|
294
|
-
cyclesThisMinute: this.cyclesThisMinute,
|
|
295
|
-
totalCycles: this.cyclesThisMinute,
|
|
296
|
-
actionType: 'init_cycle'
|
|
297
|
-
},
|
|
298
|
-
success: true
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
if (!this.runtime.llm?.isAvailable()) {
|
|
302
|
-
this.runtime.updates.raiseEvent({
|
|
303
|
-
type: 'error_occurred',
|
|
304
|
-
error: 'LLM is not configured. Please configure OpenAI or Anthropic in settings.'
|
|
305
|
-
});
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
try {
|
|
309
|
-
this.memory = await this.runtime.llm.createMemory('component', this.config.id);
|
|
310
|
-
const now = Math.floor(Date.now() / 1000);
|
|
311
|
-
await this.memory.store('initialization-time-seconds', now);
|
|
312
|
-
await this.memory.addToWorking('current-time-seconds', now);
|
|
313
|
-
const initializationPrompt = `CRITICALLY IMPORTANT: I am an autonomous agent with the following goal: ${this.config.goal}
|
|
314
|
-
|
|
315
|
-
This is my INITIALIZATION CYCLE.
|
|
316
|
-
|
|
317
|
-
My initialization cycle will take place in steps with the user providing one instruction at a time, I will perform only that instruction to completion and then await further input.
|
|
318
|
-
|
|
319
|
-
I NEED to discover the current workflow and establish my schedule and actions in order to achieve the stated goal.
|
|
320
|
-
|
|
321
|
-
My capabilities:
|
|
322
|
-
- I can discover components in the workflow using tools
|
|
323
|
-
- I can query component state and execute commands/routes using tools
|
|
324
|
-
- I can monitor events from components
|
|
325
|
-
- I have persistent memory to learn and remember across cycles, this works through the response format and the field 'memory_updates'
|
|
326
|
-
|
|
327
|
-
${RESPONSE_FORMAT}
|
|
328
|
-
${TOOL_DISCOVERY}
|
|
329
|
-
${TOOL_USAGE}
|
|
330
|
-
|
|
331
|
-
The End Result of the initialization cycle MUST be:
|
|
332
|
-
|
|
333
|
-
- I will have decided on a schedule for my actions
|
|
334
|
-
- I will have called the Tools necessary to set the Schedule Callbacks up
|
|
335
|
-
- I will have created Prompts for each of the Schedule Callbacks detailing what steps are necessary
|
|
336
|
-
- I will have stored *all* necessary Tools, Parameters, and Schemas in memory_updates, in order for the Schedule Callbacks to operate without having to perform discovery
|
|
337
|
-
|
|
338
|
-
Tool Discovery:
|
|
339
|
-
I MUST store all the necessary information required to execute the tools necessary for all of the Schedule Callback Prompts in my memory, the Cycle LLM will not have the ability to discover these
|
|
340
|
-
They should be stored in a JSON array of objects in memory_updates.tools
|
|
341
|
-
This following fields *must* be present for each type of tool
|
|
342
|
-
{componentId}_cmd_executeCommand:
|
|
343
|
-
- toolName: The exact abbreviated tool name (e.g., "osc_gfx_cmd_executeCommand")
|
|
344
|
-
- originalComponentId: The full component ID (e.g., "on_screen_graphic")
|
|
345
|
-
- description: The tool's description from discovery
|
|
346
|
-
- commandName: The command to be invoked
|
|
347
|
-
- schema: The schema for the 'parameters' of the command that needs to be sent
|
|
348
|
-
- context: If the discovery has yielded fixed values for parts of the command, I can detail them here
|
|
349
|
-
- help: A brief decription of *how* to use this tool, including what property the schema belongs to
|
|
350
|
-
{componentId}_executeRoute:
|
|
351
|
-
- toolName: The exact abbreviated tool name (e.g., "osc_gfx_active_gfx_POST")
|
|
352
|
-
- originalComponentId: The full component ID (e.g., "on_screen_graphic")
|
|
353
|
-
- description: The tool's description from discovery
|
|
354
|
-
- url: The url to execute
|
|
355
|
-
- method: The method to use
|
|
356
|
-
- schema: The schema for the body of POSTs
|
|
357
|
-
- context: If the discovery has yielded fixed values for parts of the request, I can detail them here
|
|
358
|
-
- help: A brief decription of *how* to use this tool, including what property the schema belongs to
|
|
359
|
-
|
|
360
|
-
Schedule callback:
|
|
361
|
-
I can either set up timers that will fire every set period of seconds, or I can subscribe to events using tools.
|
|
362
|
-
A detailed explanation of these will be provided by further prompts, but the result of calling these tools is that
|
|
363
|
-
- a 'cycle' will start when the callback is invoked, which involves starting a conversation with an LLM - the Cycle LLM
|
|
364
|
-
- memory will be provided to the Cycle LLM as specified in the field 'memory_updates'
|
|
365
|
-
- the cycle will loop until the LLM is satisfied it has completed the task specified by I for that schedule callback
|
|
366
|
-
|
|
367
|
-
Prompt:
|
|
368
|
-
I MUST write a prompt for each of the schedule callbacks detailing
|
|
369
|
-
- What decisions need to be made
|
|
370
|
-
- What tools need to be used to discover information necessary for that decision
|
|
371
|
-
- What tools need to be invoked with what parameters in order to execute the result of that decision
|
|
372
|
-
- The tool name MUST be provided
|
|
373
|
-
- The commandName/url/method MUST be provided when relevant
|
|
374
|
-
- The LLM MUST be urged to use the schema provided in memory
|
|
375
|
-
|
|
376
|
-
I will now WAIT to be prompted STEP BY STEP in order to achieve my initialization. Initialization is not complete until the final prompt, which means the final decision of each step should simply be 'wait'`;
|
|
377
|
-
console.log("AGENT INIT PHASE 1: Starting initial setup");
|
|
378
|
-
await this.executeWithToolLooping(initializationPrompt, `init-${Date.now()}`, 'initialization');
|
|
379
|
-
console.log("AGENT INIT PHASE 1 COMPLETED");
|
|
380
|
-
const discovery = `First you must discover all of the components, commands, routes, and events that are possibly related to the stated goal
|
|
381
|
-
|
|
382
|
-
Discover the components with
|
|
383
|
-
- workflow_listComponents
|
|
384
|
-
|
|
385
|
-
Discover the tools and events for all related components using
|
|
386
|
-
- {componentId}_cmd_listCommands
|
|
387
|
-
- {componentId}_listRoutes
|
|
388
|
-
- {componentId}_evt_listEvents
|
|
389
|
-
|
|
390
|
-
Fetch the schemas for commands / routes / events that are related to the stated goal with
|
|
391
|
-
- {componentId}_cmd_getCommandSchema
|
|
392
|
-
- {componentId}_cmd_getRouteSchema
|
|
393
|
-
- {componentId}_evt_getEventSchema
|
|
394
|
-
|
|
395
|
-
IMPORTANT: As you discover tools, record in working memory:
|
|
396
|
-
- Original component ID (e.g., "on_screen_graphic")
|
|
397
|
-
- Abbreviated tool names (e.g., "osc_gfx_active_gfx_POST")
|
|
398
|
-
- Tool descriptions (contain full functionality details)
|
|
399
|
-
- Component types and capabilities
|
|
400
|
-
|
|
401
|
-
Tool names are now abbreviated for efficiency. Use descriptions to understand functionality.
|
|
402
|
-
|
|
403
|
-
When you are satisfied you have discovered enough information to achieve the stated goal, you can WAIT for further instructions`;
|
|
404
|
-
console.log("AGENT INIT PHASE 2: Starting discovery");
|
|
405
|
-
await this.executeWithToolLooping(discovery, `init-${Date.now()}`, 'initialization');
|
|
406
|
-
console.log("AGENT INIT PHASE 2 COMPLETED");
|
|
407
|
-
const schedule = `${initializationPrompt}
|
|
408
|
-
Using the components, commands, routes, and events that you have already discovered, define a schedule for an LLM to be invoked in order to reach the stated goal
|
|
409
|
-
|
|
410
|
-
Help:
|
|
411
|
-
- Does the goal need to be performed as a reponse to specific event having taken place? Use subscribeImmediate
|
|
412
|
-
- Does the goal need to measure data from events? Use subscribeAggregated, IMPORTANT: be sure to group all related events into a single subscribe call
|
|
413
|
-
- Is the goal purely time based with no event analyis required? Use a timer: IMPORTANT: Timers are set up by calling the appropriate tool, it is *recommended* you store timerids in memory, but not required
|
|
414
|
-
|
|
415
|
-
Be very careful not to set up multiple Schedule Callbacks for the same subtask
|
|
416
|
-
- a classic mis-step is accidentally creating a subscribeAggregated call for 30s of analysis *and* a timer every 30s, that is completely unnecessary.
|
|
417
|
-
- Another classic mistake is to create multiple subscribeAggregated calls for the same task, ideally only one aggregated subscribe will exist for all related analysis
|
|
418
|
-
|
|
419
|
-
For subscribeAggregated calls, be careful to, if possible, use field extraction to only take the values that are needed in order for analysis to take place. In this case, the prompt MUST
|
|
420
|
-
specify what it is the LLM is to expect, and *how* to perform analysis on it
|
|
421
|
-
|
|
422
|
-
If you end up creating obsolete subscriptions, be sure to remove them with
|
|
423
|
-
- studio_agent_unsubscribe
|
|
424
|
-
|
|
425
|
-
For any schedule defined, CRITICAL: write a Prompt for the LLM that will be invoked as part of that schedule
|
|
426
|
-
- remembering to detail the decisions/outcome of the callback
|
|
427
|
-
- tools that must be used
|
|
428
|
-
- *how* to use the tools that must be used, including how to use the properties/schema to generate a correct request
|
|
429
|
-
|
|
430
|
-
Call the appropriate tools to set up the Schedule Callbacks, CRITICAL: Provide the Prompts that have been defined for each callback.
|
|
431
|
-
|
|
432
|
-
Once this is done, you can WAIT for further instructions`;
|
|
433
|
-
console.log("AGENT INIT PHASE 3: Starting schedule setup");
|
|
434
|
-
await this.executeWithToolLooping(schedule, `init-${Date.now()}`, 'initialization');
|
|
435
|
-
console.log("AGENT INIT PHASE 3 COMPLETED");
|
|
436
|
-
const memory = `Using the components, commands, routes, and events that you have already discovered, and schedule you have defined
|
|
437
|
-
|
|
438
|
-
- Verify that you have indeed set up the Schedule Callbacks with the Prompts that were defined for each callback
|
|
439
|
-
- Store in memory_updates
|
|
440
|
-
- components: The components you have discovered that are relevant to this task
|
|
441
|
-
- tools: The tools that are needed for each Schedule Callback, along with their parameters + schemas as initially outlined
|
|
442
|
-
|
|
443
|
-
Be sure not to store more tools than are needed, two ways of doing the same thing (IE a Command or HTTP request) is unnecessary. Prefer commands over HTTP in these cases.
|
|
444
|
-
Be sure not to store events that aren't needed
|
|
445
|
-
If a subscribeAggregate is set up for analysis, and routes are in memory that contain similar information, ensure to add to the Schedule Callback Prompt a directive to ignore the route data for disambiguation
|
|
446
|
-
|
|
447
|
-
If you've already set these properties, then perform a memory_update with the tools/components again but with the duplicate/obsolete items removed.
|
|
448
|
-
`;
|
|
449
|
-
console.log("AGENT INIT PHASE 4: Starting memory optimization");
|
|
450
|
-
await this.executeWithToolLooping(memory, `init-${Date.now()}`, 'initialization');
|
|
451
|
-
console.log("AGENT INIT PHASE 4 COMPLETED");
|
|
452
|
-
const verify = `This is the final step of initialization, you MUST verify that
|
|
453
|
-
- You have set up the necessary Schedule Callbacks with the Prompts that were defined for each callback
|
|
454
|
-
- You have stored the necessary components in memory_updates
|
|
455
|
-
- You have stored the tools in memory_updates along with their parameters + schemas
|
|
456
|
-
|
|
457
|
-
If all of things have been done already, you can stop immediately.
|
|
458
|
-
|
|
459
|
-
Once this step is complete, it will be down to the Cycle LLM to perform the stated goal and they will only have access to the memory you have created and the prompts in the Scheduled Callbacks
|
|
460
|
-
`;
|
|
461
|
-
console.log("AGENT INIT PHASE 5: Starting verification");
|
|
462
|
-
await this.executeWithToolLooping(verify, `init-${Date.now()}`, 'initialization');
|
|
463
|
-
console.log("AGENT INIT PHASE 5 COMPLETED - INITIALIZATION FINISHED");
|
|
464
|
-
this.initialized = true;
|
|
465
|
-
console.log("AGENT initialization complete, setting initialized =", this.initialized);
|
|
466
|
-
(0, logging_1.debuglog)("Agent initialization completed", {
|
|
467
|
-
componentId: this.config.id,
|
|
468
|
-
persistent_memory: await this.memory.summarizePersistent(),
|
|
469
|
-
working_memory: await this.memory.summarizeWorking(),
|
|
470
|
-
active_timers: this.activeTimers.size,
|
|
471
|
-
timer_queue: this.timerQueue.length,
|
|
472
|
-
goal: this.config.goal
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
catch (error) {
|
|
476
|
-
this.runtime.updates.raiseEvent({
|
|
477
|
-
type: 'error_occurred',
|
|
478
|
-
error: error instanceof Error ? error.message : 'Failed to initialize agent'
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
stop() {
|
|
483
|
-
if (!this.isRunning)
|
|
484
|
-
return;
|
|
485
|
-
this.isRunning = false;
|
|
486
|
-
this.isPaused = false;
|
|
487
|
-
for (const [timerId] of this.activeTimers) {
|
|
488
|
-
this.cancelTimer(timerId);
|
|
489
|
-
}
|
|
490
|
-
this.timerQueue = [];
|
|
491
|
-
this.initializationHistory = [];
|
|
492
|
-
this.initialized = false;
|
|
493
|
-
for (const [subscriptionId] of this.immediateSubscriptions) {
|
|
494
|
-
this.unsubscribeEvent(subscriptionId);
|
|
495
|
-
}
|
|
496
|
-
for (const [subscriptionId] of this.aggregatedSubscriptions) {
|
|
497
|
-
this.unsubscribeEvent(subscriptionId);
|
|
498
|
-
}
|
|
499
|
-
this.runtime.updates.raiseEvent({
|
|
500
|
-
type: 'agent_stopped',
|
|
501
|
-
timestamp: new Date().toISOString()
|
|
502
|
-
});
|
|
503
|
-
}
|
|
504
|
-
pause() {
|
|
505
|
-
this.isPaused = true;
|
|
506
|
-
}
|
|
507
|
-
resume() {
|
|
508
|
-
this.isPaused = false;
|
|
509
|
-
}
|
|
510
|
-
async handleHttpRequest(url, method) {
|
|
511
|
-
if (!this.memory) {
|
|
512
|
-
return { error: 'Agent memory not initialized' };
|
|
513
|
-
}
|
|
514
|
-
try {
|
|
515
|
-
switch (`${method.toUpperCase()} ${url}`) {
|
|
516
|
-
case 'GET /memory/working': {
|
|
517
|
-
const working = await this.memory.getWorking();
|
|
518
|
-
return {
|
|
519
|
-
type: 'working_memory',
|
|
520
|
-
data: working,
|
|
521
|
-
timestamp: new Date().toISOString()
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
case 'GET /memory/persistent': {
|
|
525
|
-
const persistent = await this.memory.getPersistent();
|
|
526
|
-
return {
|
|
527
|
-
type: 'persistent_memory',
|
|
528
|
-
data: persistent,
|
|
529
|
-
timestamp: new Date().toISOString()
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
case 'GET /memory/summary': {
|
|
533
|
-
const working = await this.memory.getWorking();
|
|
534
|
-
const persistent = await this.memory.getPersistent();
|
|
535
|
-
return {
|
|
536
|
-
type: 'memory_summary',
|
|
537
|
-
working_memory: working,
|
|
538
|
-
persistent_memory: persistent,
|
|
539
|
-
timestamp: new Date().toISOString()
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
case 'GET /status/detailed': {
|
|
543
|
-
const working = await this.memory.getWorking();
|
|
544
|
-
const persistent = await this.memory.getPersistent();
|
|
545
|
-
return {
|
|
546
|
-
type: 'detailed_status',
|
|
547
|
-
agent_status: {
|
|
548
|
-
is_running: this.isRunning,
|
|
549
|
-
is_paused: this.isPaused,
|
|
550
|
-
initialized: this.initialized,
|
|
551
|
-
cycles_this_minute: this.cyclesThisMinute,
|
|
552
|
-
total_cycles: this.totalCycles,
|
|
553
|
-
},
|
|
554
|
-
goal: this.config.goal,
|
|
555
|
-
system_prompt: this.config.systemPrompt,
|
|
556
|
-
memory: {
|
|
557
|
-
working: working,
|
|
558
|
-
persistent: persistent
|
|
559
|
-
},
|
|
560
|
-
timestamp: new Date().toISOString()
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
default:
|
|
564
|
-
return { error: `Unknown endpoint: ${method} ${url}` };
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
catch (error) {
|
|
568
|
-
return {
|
|
569
|
-
error: `Failed to handle request: ${error instanceof Error ? error.message : 'Unknown error'}`
|
|
570
|
-
};
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
async makeDecision(cyclePrompt, additionalMemoryValues) {
|
|
574
|
-
console.log("AGENT makeDecision called - cyclePrompt:", cyclePrompt.substring(0, 100));
|
|
575
|
-
(0, logging_1.debuglog)("=== MAKE DECISION CALLED ===", {
|
|
576
|
-
cyclePrompt: cyclePrompt.substring(0, 100),
|
|
577
|
-
additionalMemoryValues: Object.keys(additionalMemoryValues || {}),
|
|
578
|
-
currentCycles: this.cyclesThisMinute,
|
|
579
|
-
totalCycles: this.totalCycles,
|
|
580
|
-
isExecutingCycle: this.isExecutingCycle
|
|
581
|
-
});
|
|
582
|
-
this.cyclesThisMinute++;
|
|
583
|
-
this.totalCycles++;
|
|
584
|
-
if (this.cyclesThisMinute > (this.config.maxCyclesPerMinute ?? 6)) {
|
|
585
|
-
(0, logging_1.warninglog)("Too many cycles in one minute, skipping work", {
|
|
586
|
-
cyclesThisMinute: this.cyclesThisMinute,
|
|
587
|
-
maxCyclesPerMinute: this.config.maxCyclesPerMinute
|
|
588
|
-
});
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
if (!this.memory) {
|
|
592
|
-
(0, logging_1.debuglog)("No memory available, aborting decision");
|
|
593
|
-
this.runtime.updates.raiseEvent({
|
|
594
|
-
type: 'error_occurred',
|
|
595
|
-
error: 'Agent memory not initialized'
|
|
596
|
-
});
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
if (this.isExecutingCycle) {
|
|
600
|
-
(0, logging_1.debuglog)("Already executing cycle, returning early");
|
|
601
|
-
return;
|
|
602
|
-
}
|
|
603
|
-
(0, logging_1.debuglog)("Setting isExecutingCycle = true, starting decision");
|
|
604
|
-
this.isExecutingCycle = true;
|
|
605
|
-
try {
|
|
606
|
-
const now = Math.floor(Date.now() / 1000);
|
|
607
|
-
await this.memory.addToWorking('current-time-seconds', now);
|
|
608
|
-
await this.memory.addToWorking('total-cycles', this.totalCycles);
|
|
609
|
-
await this.memory.addToWorking('cycles-this-minute', this.cyclesThisMinute);
|
|
610
|
-
if (additionalMemoryValues) {
|
|
611
|
-
for (const [key, value] of Object.entries(additionalMemoryValues)) {
|
|
612
|
-
if (key !== 'timer_events' && key !== 'immediate_events') {
|
|
613
|
-
await this.memory.addToWorking(key, value);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
let prompt = `CONTEXT:
|
|
618
|
-
CRITICALLY IMPORTANT: Overall Goal: ${this.config.goal}
|
|
619
|
-
|
|
620
|
-
The current time is in memory, with the key 'current-time-seconds'.`;
|
|
621
|
-
prompt += `
|
|
622
|
-
|
|
623
|
-
🎯 SPECIFIC TASK FOR THIS CYCLE:
|
|
624
|
-
${cyclePrompt}
|
|
625
|
-
|
|
626
|
-
CRITICAL: This cycle prompt above is your PRIMARY DIRECTIVE. Focus exclusively on this specific task. All tool usage must align with completing this specific task.`;
|
|
627
|
-
prompt += `
|
|
628
|
-
|
|
629
|
-
DECISION CRITERIA:
|
|
630
|
-
- Handle any timer_events that have fired - these represent scheduled actions
|
|
631
|
-
- Handle any immediate_events from components - these need quick response
|
|
632
|
-
- Process any aggregated event data that's ready for analysis
|
|
633
|
-
- If nothing needs to be done right now, that's fine - just document your decision
|
|
634
|
-
- CRITICAL: Your 'decision' field must accurately reflect what you're actually doing
|
|
635
|
-
|
|
636
|
-
TOOL EXECUTION: You must use only the tools you already know about in your persistent memory. DO NOT USE any other tools.
|
|
637
|
-
|
|
638
|
-
${TOOL_USAGE}
|
|
639
|
-
|
|
640
|
-
🔍 SCHEMA ADHERENCE IS MANDATORY:
|
|
641
|
-
- Use the schemas provided in the your persistent memory for request body / command parameters
|
|
642
|
-
- Every parameter must match the schema type and requirements EXACTLY
|
|
643
|
-
- Do NOT guess parameter values - use the schema as your authoritative guide
|
|
644
|
-
- If a schema specifies required fields, ALL required fields MUST be provided
|
|
645
|
-
|
|
646
|
-
If you end up having to perform discovery, you MUST store any relevant findings in memory_updates.findings for future cycles
|
|
647
|
-
|
|
648
|
-
${RESPONSE_FORMAT}
|
|
649
|
-
`;
|
|
650
|
-
(0, logging_1.debuglog)("About to call executeWithToolLooping for decision");
|
|
651
|
-
await this.executeWithToolLooping(prompt, `decision-${Date.now()}`, 'decision');
|
|
652
|
-
(0, logging_1.debuglog)("executeWithToolLooping completed for decision");
|
|
653
|
-
}
|
|
654
|
-
catch (error) {
|
|
655
|
-
(0, logging_1.debuglog)("Error in makeDecision", { error: error instanceof Error ? error.message : error });
|
|
656
|
-
this.runtime.updates.raiseEvent({
|
|
657
|
-
type: 'error_occurred',
|
|
658
|
-
error: error instanceof Error ? error.message : 'Unknown error during decision making'
|
|
659
|
-
});
|
|
660
|
-
}
|
|
661
|
-
finally {
|
|
662
|
-
(0, logging_1.debuglog)("=== MAKE DECISION COMPLETED, setting isExecutingCycle = false ===");
|
|
663
|
-
this.isExecutingCycle = false;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
async parseStructuredResponse(content) {
|
|
667
|
-
try {
|
|
668
|
-
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
669
|
-
if (jsonMatch) {
|
|
670
|
-
return JSON.parse(jsonMatch[0]);
|
|
671
|
-
}
|
|
672
|
-
return null;
|
|
673
|
-
}
|
|
674
|
-
catch (_error) {
|
|
675
|
-
return null;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
setTimer(timerId, delaySeconds, cyclePrompt, recurring = false) {
|
|
679
|
-
this.cancelTimer(timerId);
|
|
680
|
-
const fireTimer = () => {
|
|
681
|
-
this.timerQueue.push({
|
|
682
|
-
timerId,
|
|
683
|
-
cyclePrompt,
|
|
684
|
-
firedAt: new Date().toISOString(),
|
|
685
|
-
recurring,
|
|
686
|
-
delaySeconds
|
|
687
|
-
});
|
|
688
|
-
if (!this.isExecutingCycle) {
|
|
689
|
-
void this.processTimerQueue();
|
|
690
|
-
}
|
|
691
|
-
};
|
|
692
|
-
const timeout = setTimeout(fireTimer, delaySeconds * 1000);
|
|
693
|
-
this.activeTimers.set(timerId, { timeout, recurring, delaySeconds, cyclePrompt });
|
|
694
|
-
}
|
|
695
|
-
cancelTimer(timerId) {
|
|
696
|
-
const timer = this.activeTimers.get(timerId);
|
|
697
|
-
if (timer) {
|
|
698
|
-
clearTimeout(timer.timeout);
|
|
699
|
-
this.activeTimers.delete(timerId);
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
async subscribeImmediate(componentId, eventType, cyclePrompt) {
|
|
703
|
-
const subscriptionId = `immediate_${componentId}_${eventType}`;
|
|
704
|
-
this.unsubscribeEvent(subscriptionId);
|
|
705
|
-
const callback = async (event) => {
|
|
706
|
-
if (event && event.type === eventType) {
|
|
707
|
-
if (!this.isExecutingCycle) {
|
|
708
|
-
void this.processImmediateEvent(componentId, eventType, cyclePrompt, event);
|
|
709
|
-
}
|
|
710
|
-
else {
|
|
711
|
-
void this.processImmediateEvent(componentId, eventType, cyclePrompt, event);
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
};
|
|
715
|
-
this.runtime.shared.subscribeToComponentEvents(componentId, callback);
|
|
716
|
-
this.immediateSubscriptions.set(subscriptionId, {
|
|
717
|
-
componentId,
|
|
718
|
-
eventType,
|
|
719
|
-
cyclePrompt,
|
|
720
|
-
callback
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
async processImmediateEvent(componentId, eventType, cyclePrompt, event) {
|
|
724
|
-
if (!this.memory)
|
|
725
|
-
return;
|
|
726
|
-
const additionalMemoryValues = {};
|
|
727
|
-
const immediateEvents = [{ componentId, eventType, cyclePrompt, payload: event, timestamp: new Date().toISOString() }];
|
|
728
|
-
additionalMemoryValues.immediate_events = immediateEvents;
|
|
729
|
-
if (!this.isExecutingCycle) {
|
|
730
|
-
(0, logging_1.debuglog)("processImmediateEvent triggering makeDecision", {
|
|
731
|
-
componentId,
|
|
732
|
-
eventType,
|
|
733
|
-
cyclePrompt: cyclePrompt.substring(0, 50)
|
|
734
|
-
});
|
|
735
|
-
await this.makeDecision(cyclePrompt, additionalMemoryValues);
|
|
736
|
-
}
|
|
737
|
-
else {
|
|
738
|
-
(0, logging_1.debuglog)("processImmediateEvent skipped - already executing cycle", {
|
|
739
|
-
componentId,
|
|
740
|
-
eventType
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
extractFieldFromPayload(payload, fieldPath) {
|
|
745
|
-
if (!fieldPath || !payload || typeof payload !== 'object') {
|
|
746
|
-
return payload;
|
|
747
|
-
}
|
|
748
|
-
const parts = fieldPath.split('.');
|
|
749
|
-
let current = payload;
|
|
750
|
-
for (const part of parts) {
|
|
751
|
-
if (current && typeof current === 'object' && part in current) {
|
|
752
|
-
current = current[part];
|
|
753
|
-
}
|
|
754
|
-
else {
|
|
755
|
-
return payload;
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
return current;
|
|
759
|
-
}
|
|
760
|
-
subscribeAggregated(subscriptionId, sources, windowSeconds, retentionSeconds, cyclePrompt) {
|
|
761
|
-
this.unsubscribeEvent(subscriptionId);
|
|
762
|
-
const eventBuffer = new Map();
|
|
763
|
-
const callbacks = [];
|
|
764
|
-
const componentSources = new Map();
|
|
765
|
-
for (const source of sources) {
|
|
766
|
-
if (!componentSources.has(source.componentId)) {
|
|
767
|
-
componentSources.set(source.componentId, []);
|
|
768
|
-
}
|
|
769
|
-
componentSources.get(source.componentId).push({ eventType: source.eventType, fieldPath: source.fieldPath });
|
|
770
|
-
const sourceKey = `${source.componentId}_${source.eventType}`;
|
|
771
|
-
eventBuffer.set(sourceKey, []);
|
|
772
|
-
}
|
|
773
|
-
for (const [componentId, eventTypesWithPaths] of componentSources) {
|
|
774
|
-
const callback = async (event) => {
|
|
775
|
-
if (event) {
|
|
776
|
-
const eventType = event.type;
|
|
777
|
-
const matchingSource = eventTypesWithPaths.find(s => s.eventType === eventType);
|
|
778
|
-
if (matchingSource) {
|
|
779
|
-
const sourceKey = `${componentId}_${eventType}`;
|
|
780
|
-
const now = Date.now();
|
|
781
|
-
const buffer = eventBuffer.get(sourceKey) || [];
|
|
782
|
-
const extractedPayload = this.extractFieldFromPayload(event, matchingSource.fieldPath);
|
|
783
|
-
buffer.push({ payload: extractedPayload, timestamp: now });
|
|
784
|
-
const cutoffTime = now - (retentionSeconds * 1000);
|
|
785
|
-
const filteredBuffer = buffer.filter(e => e.timestamp > cutoffTime);
|
|
786
|
-
eventBuffer.set(sourceKey, filteredBuffer);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
};
|
|
790
|
-
this.runtime.shared.subscribeToComponentEvents(componentId, callback);
|
|
791
|
-
callbacks.push({ componentId, callback });
|
|
792
|
-
}
|
|
793
|
-
this.aggregatedSubscriptions.set(subscriptionId, {
|
|
794
|
-
sources,
|
|
795
|
-
windowSeconds,
|
|
796
|
-
retentionSeconds,
|
|
797
|
-
cyclePrompt,
|
|
798
|
-
lastProcessedAt: Date.now(),
|
|
799
|
-
eventBuffer,
|
|
800
|
-
callbacks
|
|
801
|
-
});
|
|
802
|
-
this.setTimer(`aggregated_${subscriptionId}`, windowSeconds, `Process aggregated data for ${subscriptionId}`, true);
|
|
803
|
-
}
|
|
804
|
-
unsubscribeEvent(subscriptionId) {
|
|
805
|
-
if (subscriptionId.startsWith('immediate_')) {
|
|
806
|
-
const subscription = this.immediateSubscriptions.get(subscriptionId);
|
|
807
|
-
if (subscription) {
|
|
808
|
-
this.runtime.shared.unsubscribeToComponentEvents(subscription.componentId, subscription.callback);
|
|
809
|
-
this.immediateSubscriptions.delete(subscriptionId);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
const aggregatedSub = this.aggregatedSubscriptions.get(subscriptionId);
|
|
813
|
-
if (aggregatedSub) {
|
|
814
|
-
for (const { componentId, callback } of aggregatedSub.callbacks) {
|
|
815
|
-
this.runtime.shared.unsubscribeToComponentEvents(componentId, callback);
|
|
816
|
-
}
|
|
817
|
-
this.cancelTimer(`aggregated_${subscriptionId}`);
|
|
818
|
-
this.aggregatedSubscriptions.delete(subscriptionId);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
async processTimerQueue() {
|
|
822
|
-
(0, logging_1.debuglog)("processTimerQueue called", {
|
|
823
|
-
isExecutingCycle: this.isExecutingCycle,
|
|
824
|
-
queueLength: this.timerQueue.length,
|
|
825
|
-
queueTimers: this.timerQueue.map(t => ({ id: t.timerId, prompt: t.cyclePrompt.substring(0, 30) }))
|
|
826
|
-
});
|
|
827
|
-
if (this.isExecutingCycle || this.timerQueue.length === 0) {
|
|
828
|
-
(0, logging_1.debuglog)("processTimerQueue early return", {
|
|
829
|
-
isExecutingCycle: this.isExecutingCycle,
|
|
830
|
-
queueLength: this.timerQueue.length
|
|
831
|
-
});
|
|
832
|
-
return;
|
|
833
|
-
}
|
|
834
|
-
(0, logging_1.debuglog)("processTimerQueue setting isExecutingCycle = true");
|
|
835
|
-
this.isExecutingCycle = true;
|
|
836
|
-
try {
|
|
837
|
-
const timer = this.timerQueue.shift();
|
|
838
|
-
const additionalMemoryValues = {};
|
|
839
|
-
if (this.memory) {
|
|
840
|
-
const timerEvents = [{
|
|
841
|
-
timerId: timer.timerId,
|
|
842
|
-
cyclePrompt: timer.cyclePrompt,
|
|
843
|
-
firedAt: timer.firedAt
|
|
844
|
-
}];
|
|
845
|
-
additionalMemoryValues.timer_events = timerEvents;
|
|
846
|
-
if (timer.timerId.startsWith('aggregated_')) {
|
|
847
|
-
const subscriptionId = timer.timerId.replace('aggregated_', '');
|
|
848
|
-
const subscription = this.aggregatedSubscriptions.get(subscriptionId);
|
|
849
|
-
if (subscription) {
|
|
850
|
-
const aggregatedData = {};
|
|
851
|
-
for (const [sourceKey, buffer] of subscription.eventBuffer) {
|
|
852
|
-
aggregatedData[sourceKey] = [...buffer];
|
|
853
|
-
}
|
|
854
|
-
await this.memory.store(subscriptionId, aggregatedData);
|
|
855
|
-
subscription.lastProcessedAt = Date.now();
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
(0, logging_1.debuglog)("processTimerQueue triggering makeDecision", {
|
|
860
|
-
timerId: timer.timerId,
|
|
861
|
-
cyclePrompt: timer.cyclePrompt.substring(0, 50),
|
|
862
|
-
recurring: timer.recurring,
|
|
863
|
-
delaySeconds: timer.delaySeconds
|
|
864
|
-
});
|
|
865
|
-
await this.makeDecision(timer.cyclePrompt, additionalMemoryValues);
|
|
866
|
-
if (timer.recurring && timer.delaySeconds) {
|
|
867
|
-
const fireTimer = () => {
|
|
868
|
-
this.timerQueue.push({
|
|
869
|
-
timerId: timer.timerId,
|
|
870
|
-
cyclePrompt: timer.cyclePrompt,
|
|
871
|
-
firedAt: new Date().toISOString(),
|
|
872
|
-
recurring: timer.recurring,
|
|
873
|
-
delaySeconds: timer.delaySeconds
|
|
874
|
-
});
|
|
875
|
-
if (!this.isExecutingCycle) {
|
|
876
|
-
void this.processTimerQueue();
|
|
877
|
-
}
|
|
878
|
-
};
|
|
879
|
-
const timeout = setTimeout(fireTimer, timer.delaySeconds * 1000);
|
|
880
|
-
this.activeTimers.set(timer.timerId, {
|
|
881
|
-
timeout,
|
|
882
|
-
recurring: timer.recurring,
|
|
883
|
-
delaySeconds: timer.delaySeconds,
|
|
884
|
-
cyclePrompt: timer.cyclePrompt
|
|
885
|
-
});
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
catch (error) {
|
|
889
|
-
this.runtime.updates.raiseEvent({
|
|
890
|
-
type: 'error_occurred',
|
|
891
|
-
error: error instanceof Error ? error.message : 'Timer processing error'
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
finally {
|
|
895
|
-
(0, logging_1.debuglog)("processTimerQueue finally block - setting isExecutingCycle = false", {
|
|
896
|
-
remainingQueueLength: this.timerQueue.length
|
|
897
|
-
});
|
|
898
|
-
this.isExecutingCycle = false;
|
|
899
|
-
if (this.timerQueue.length > 0) {
|
|
900
|
-
(0, logging_1.debuglog)("processTimerQueue scheduling next timer processing");
|
|
901
|
-
void this.processTimerQueue();
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
(0, logging_1.debuglog)("processTimerQueue no more timers to process");
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
async executeTool(name, args) {
|
|
909
|
-
return this.handleAgentTool(name, args);
|
|
910
|
-
}
|
|
911
|
-
async handleAgentTool(toolName, args) {
|
|
912
|
-
switch (toolName) {
|
|
913
|
-
case 'studio_agent_subscribeImmediate': {
|
|
914
|
-
const { componentId, eventType, cyclePrompt } = args;
|
|
915
|
-
if (!componentId || !eventType || !cyclePrompt) {
|
|
916
|
-
throw new Error('Missing required fields: componentId, eventType, cyclePrompt');
|
|
917
|
-
}
|
|
918
|
-
await this.subscribeImmediate(componentId, eventType, cyclePrompt);
|
|
919
|
-
return {
|
|
920
|
-
success: true,
|
|
921
|
-
message: `Subscribed to immediate events: ${eventType} from ${componentId}`,
|
|
922
|
-
subscriptionId: `immediate_${componentId}_${eventType}`
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
case 'studio_agent_subscribeAggregated': {
|
|
926
|
-
const { subscriptionId, sources, windowSeconds, retentionSeconds, cyclePrompt } = args;
|
|
927
|
-
if (!subscriptionId || !sources || !windowSeconds || !cyclePrompt) {
|
|
928
|
-
throw new Error('Missing required fields: subscriptionId, sources, windowSeconds, cyclePrompt');
|
|
929
|
-
}
|
|
930
|
-
const retention = retentionSeconds || windowSeconds;
|
|
931
|
-
this.subscribeAggregated(subscriptionId, sources, windowSeconds, retention, cyclePrompt);
|
|
932
|
-
return {
|
|
933
|
-
success: true,
|
|
934
|
-
message: `Created aggregated subscription: ${subscriptionId}`,
|
|
935
|
-
subscriptionId,
|
|
936
|
-
sourcesCount: sources.length
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
case 'studio_agent_unsubscribe': {
|
|
940
|
-
const { subscriptionId } = args;
|
|
941
|
-
if (!subscriptionId) {
|
|
942
|
-
throw new Error('Missing required field: subscriptionId');
|
|
943
|
-
}
|
|
944
|
-
this.unsubscribeEvent(subscriptionId);
|
|
945
|
-
return {
|
|
946
|
-
success: true,
|
|
947
|
-
message: `Unsubscribed from: ${subscriptionId}`
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
case 'studio_agent_setTimer': {
|
|
951
|
-
const { timerId, delaySeconds, cyclePrompt, recurring } = args;
|
|
952
|
-
if (!timerId || !delaySeconds || !cyclePrompt) {
|
|
953
|
-
throw new Error('Missing required fields: timerId, delaySeconds, cyclePrompt');
|
|
954
|
-
}
|
|
955
|
-
this.setTimer(timerId, delaySeconds, cyclePrompt, recurring || false);
|
|
956
|
-
return {
|
|
957
|
-
success: true,
|
|
958
|
-
message: `Timer set: ${timerId} will fire in ${delaySeconds}s`,
|
|
959
|
-
timerId,
|
|
960
|
-
delaySeconds,
|
|
961
|
-
recurring: recurring || false
|
|
962
|
-
};
|
|
963
|
-
}
|
|
964
|
-
case 'studio_agent_cancelTimer': {
|
|
965
|
-
const { timerId } = args;
|
|
966
|
-
if (!timerId) {
|
|
967
|
-
throw new Error('Missing required field: timerId');
|
|
968
|
-
}
|
|
969
|
-
this.cancelTimer(timerId);
|
|
970
|
-
return {
|
|
971
|
-
success: true,
|
|
972
|
-
message: `Timer cancelled: ${timerId}`
|
|
973
|
-
};
|
|
974
|
-
}
|
|
975
|
-
case 'studio_agent_listSubscriptions': {
|
|
976
|
-
const timers = Array.from(this.activeTimers.entries()).map(([id, timer]) => ({
|
|
977
|
-
timerId: id,
|
|
978
|
-
recurring: timer.recurring,
|
|
979
|
-
delaySeconds: timer.delaySeconds,
|
|
980
|
-
cyclePrompt: timer.cyclePrompt
|
|
981
|
-
}));
|
|
982
|
-
const immediate = Array.from(this.immediateSubscriptions.entries()).map(([id, sub]) => ({
|
|
983
|
-
subscriptionId: id,
|
|
984
|
-
componentId: sub.componentId,
|
|
985
|
-
eventType: sub.eventType,
|
|
986
|
-
cyclePrompt: sub.cyclePrompt
|
|
987
|
-
}));
|
|
988
|
-
const aggregated = Array.from(this.aggregatedSubscriptions.entries()).map(([id, sub]) => ({
|
|
989
|
-
subscriptionId: id,
|
|
990
|
-
sources: sub.sources,
|
|
991
|
-
windowSeconds: sub.windowSeconds,
|
|
992
|
-
retentionSeconds: sub.retentionSeconds,
|
|
993
|
-
cyclePrompt: sub.cyclePrompt
|
|
994
|
-
}));
|
|
995
|
-
const totalCount = timers.length + immediate.length + aggregated.length;
|
|
996
|
-
return {
|
|
997
|
-
immediate,
|
|
998
|
-
aggregated,
|
|
999
|
-
timers,
|
|
1000
|
-
message: totalCount > 0 ? `${totalCount} active subscription(s) and timer(s)` : 'No active subscriptions or timers'
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
default:
|
|
1004
|
-
throw new Error(`Unknown agent tool: ${toolName}`);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
async executeWithToolLooping(initialPrompt, actionId, cycleType) {
|
|
1008
|
-
console.log("AGENT executeWithToolLooping called - cycleType:", cycleType, "prompt:", initialPrompt.substring(0, 100));
|
|
1009
|
-
console.log("AGENT executeWithToolLooping - ENTRY POINT");
|
|
1010
|
-
if (!this.memory) {
|
|
1011
|
-
console.log("AGENT no memory available!");
|
|
1012
|
-
this.runtime.updates.raiseEvent({
|
|
1013
|
-
type: 'error_occurred',
|
|
1014
|
-
error: 'Agent memory not initialized'
|
|
1015
|
-
});
|
|
1016
|
-
return;
|
|
1017
|
-
}
|
|
1018
|
-
try {
|
|
1019
|
-
let systemPrompt = this.config.systemPrompt;
|
|
1020
|
-
let messages = [];
|
|
1021
|
-
if (cycleType === 'initialization') {
|
|
1022
|
-
this.initializationHistory.push({
|
|
1023
|
-
role: 'user',
|
|
1024
|
-
content: initialPrompt
|
|
1025
|
-
});
|
|
1026
|
-
messages = [...this.initializationHistory];
|
|
1027
|
-
}
|
|
1028
|
-
else {
|
|
1029
|
-
const persistentMemory = await this.memory.summarizePersistent();
|
|
1030
|
-
if (persistentMemory) {
|
|
1031
|
-
systemPrompt += `\n\nPersistent Memory (tools and components discovered during initialization):\n${persistentMemory}`;
|
|
1032
|
-
}
|
|
1033
|
-
messages = [
|
|
1034
|
-
{
|
|
1035
|
-
role: 'user',
|
|
1036
|
-
content: initialPrompt
|
|
1037
|
-
}
|
|
1038
|
-
];
|
|
1039
|
-
}
|
|
1040
|
-
const workflowOptions = {
|
|
1041
|
-
systemPrompt,
|
|
1042
|
-
temperature: 0.3,
|
|
1043
|
-
maxTokens: 2000,
|
|
1044
|
-
toolProviders: [this],
|
|
1045
|
-
messages,
|
|
1046
|
-
onToolExecution: (toolName, args) => {
|
|
1047
|
-
console.log(`AGENT TOOL EXECUTION: ${toolName}`, args);
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
console.log("AGENT DEBUG - executeWorkflowRequest being called with:");
|
|
1051
|
-
console.log("- cycleType:", cycleType);
|
|
1052
|
-
console.log("- systemPrompt length:", systemPrompt.length);
|
|
1053
|
-
console.log("- messages count:", messages.length);
|
|
1054
|
-
console.log("- toolProviders count:", workflowOptions.toolProviders.length);
|
|
1055
|
-
console.log("- messages:", JSON.stringify(messages, null, 2));
|
|
1056
|
-
console.log("AGENT - About to call executeWorkflowRequest");
|
|
1057
|
-
const result = await this.runtime.llm.executeWorkflowRequest(initialPrompt, this.memory, workflowOptions);
|
|
1058
|
-
console.log("AGENT - executeWorkflowRequest completed");
|
|
1059
|
-
console.log("AGENT LLM RESPONSE - toolCallsExecuted:", result.toolCallsExecuted);
|
|
1060
|
-
console.log("AGENT LLM RESPONSE - stepLimitReached:", result.stepLimitReached);
|
|
1061
|
-
console.log("AGENT LLM RESPONSE - content length:", result.content?.length || 0);
|
|
1062
|
-
console.log("AGENT LLM RESPONSE - content:", result.content);
|
|
1063
|
-
const structuredResponse = await this.parseStructuredResponse(result.content);
|
|
1064
|
-
if (structuredResponse?.memory_updates) {
|
|
1065
|
-
for (const [key, value] of Object.entries(structuredResponse.memory_updates)) {
|
|
1066
|
-
if (value !== undefined && value !== null) {
|
|
1067
|
-
(0, logging_1.debuglog)("Storing memory", { key, value });
|
|
1068
|
-
await this.memory.store(key, value);
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
if (cycleType === 'initialization') {
|
|
1073
|
-
this.initializationHistory.push({
|
|
1074
|
-
role: 'assistant',
|
|
1075
|
-
content: result.content
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
this.runtime.updates.raiseEvent({
|
|
1079
|
-
type: 'action_taken',
|
|
1080
|
-
action: {
|
|
1081
|
-
id: actionId,
|
|
1082
|
-
type: cycleType === 'initialization' ? 'analysis' : 'analysis',
|
|
1083
|
-
timestamp: new Date().toISOString(),
|
|
1084
|
-
description: structuredResponse?.decision || result.content || `${cycleType} completed`,
|
|
1085
|
-
result: structuredResponse ? { structured_response: structuredResponse } : { raw_response: result.content },
|
|
1086
|
-
parameters: { toolCallsExecuted: result.toolCallsExecuted || 0, cycleType },
|
|
1087
|
-
success: true
|
|
1088
|
-
}
|
|
1089
|
-
});
|
|
1090
|
-
if (structuredResponse?.why) {
|
|
1091
|
-
await this.memory?.store('last-cycle-why', structuredResponse.why);
|
|
1092
|
-
}
|
|
1093
|
-
if (structuredResponse?.decision) {
|
|
1094
|
-
await this.memory?.store('last-cycle-decision', structuredResponse.decision);
|
|
1095
|
-
}
|
|
1096
|
-
console.log("AGENT executeWithToolLooping completed successfully");
|
|
1097
|
-
}
|
|
1098
|
-
catch (error) {
|
|
1099
|
-
console.log("AGENT executeWithToolLooping caught error:", error);
|
|
1100
|
-
this.runtime.updates.raiseEvent({
|
|
1101
|
-
type: 'error_occurred',
|
|
1102
|
-
error: error instanceof Error ? error.message : 'Unknown error during tool execution'
|
|
1103
|
-
});
|
|
1104
|
-
throw error;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
const RESPONSE_FORMAT = `
|
|
1109
|
-
IMPORTANT: You must respond in the following JSON format for ALL responses (specified below as a typescript record for convenience):
|
|
1110
|
-
|
|
1111
|
-
BEFORE FILLING THIS JSON: First calculate your final decision. If action is NOT due yet, your decision MUST be "wait" or "not to act".
|
|
1112
|
-
IMPORTANT: DO NOT INCLUDE THE COMMENTS, RESULTM MUST BE VALID JSON
|
|
1113
|
-
|
|
1114
|
-
{
|
|
1115
|
-
/* ANALYSIS FIRST: Calculate timing and scheduling and determine if action is due
|
|
1116
|
-
Show your calculations here - current time, last executed time, difference, required interval, data thresholds, etc
|
|
1117
|
-
This determines what your decision will be */
|
|
1118
|
-
why: string,
|
|
1119
|
-
|
|
1120
|
-
/* Based on the analysis above, what did you ACTUALLY decide?
|
|
1121
|
-
- If calculation shows action is NOT due: "I decided to wait for the next cycle"
|
|
1122
|
-
- If calculation shows action IS due: "I decided to [specific action]"
|
|
1123
|
-
- MUST match the conclusion from your 'why' analysis above */
|
|
1124
|
-
decision: string,
|
|
1125
|
-
|
|
1126
|
-
/* the category of the decision made/action taken, if execute_task is returned then native function calling for any tools needed should be used to execute it
|
|
1127
|
-
- execute_task: We will loop again and allow you to perform actions
|
|
1128
|
-
- discovery: We will loop again and allow you to perform actions
|
|
1129
|
-
- wait: We will stop looping and wait for the next cycle
|
|
1130
|
-
- finished: We will stop looping and wait for the next cycle
|
|
1131
|
-
*/
|
|
1132
|
-
action_type: 'execute_task' | 'monitor' | 'wait' | 'discovery' | 'finished',
|
|
1133
|
-
|
|
1134
|
-
/* CRITICAL FOR INITIALIZATION: Store discovered components, routes
|
|
1135
|
-
Example keys:
|
|
1136
|
-
- components: JSON array of component ids/types that are relevant to this agent's job
|
|
1137
|
-
- tools: JSON array of the tools necessary to do this agent's job
|
|
1138
|
-
- findings: An array that should be appended to with any useful information that is discovered during a cycle
|
|
1139
|
-
memory_updates: {
|
|
1140
|
-
components?: { id: string, type: string }[],
|
|
1141
|
-
active_timers?: { id: string, name: string }[],
|
|
1142
|
-
active_subscriptions?: { id: string, name: string }[],
|
|
1143
|
-
tools?: {
|
|
1144
|
-
name: string,
|
|
1145
|
-
description: string,
|
|
1146
|
-
componentId: string,
|
|
1147
|
-
commandName?: string,
|
|
1148
|
-
url?: string,
|
|
1149
|
-
method?: string,
|
|
1150
|
-
schema?: string,
|
|
1151
|
-
context?: string
|
|
1152
|
-
}[],
|
|
1153
|
-
findings: string[]
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
/* Current status of this session*/
|
|
1157
|
-
status: 'analyzing' | 'executing' | 'monitoring' | 'waiting'
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
Respond ONLY with this valid JSON. Use native function calling for any tools you need to execute. If you say you are going to execute a tool, then make sure you include the native function calls alongside this response`;
|
|
1161
|
-
const TOOL_USAGE = `USING THESE TOOLS:
|
|
1162
|
-
IMPORTANT:
|
|
1163
|
-
If commandName is present, it is likely an executeCommand tool
|
|
1164
|
-
If url/method are present, it is likely an executeRoute tool
|
|
1165
|
-
|
|
1166
|
-
- When using executeCommand tools, the parameters are
|
|
1167
|
-
- parameters: The actual body of the command, this is what the Schema defines
|
|
1168
|
-
- commandName: The name of the command to execute, this is mandatory
|
|
1169
|
-
|
|
1170
|
-
- When using executeRoute tools, the parameters are
|
|
1171
|
-
- body: The actual body of the command, this is what the Schema defines
|
|
1172
|
-
- url: The url of the route to execute, this is mandatory
|
|
1173
|
-
- method: The method of the route to execute, this is mandatory
|
|
1174
|
-
|
|
1175
|
-
- Prefer executeCommand over executeRoute when both are available
|
|
1176
|
-
- Use executeRoute When executeCommand is not available or doesn't have the needed functionality
|
|
1177
|
-
`;
|
|
1178
|
-
const TOOL_DISCOVERY = `
|
|
1179
|
-
CRITICAL TOOL RULES:
|
|
1180
|
-
- Tools CANNOT be guessed or assumed - they MUST be discovered
|
|
1181
|
-
- Component IDs are NOT predictable - you MUST discover them first
|
|
1182
|
-
- If a tool call fails with "not found", you haven't discovered it properly
|
|
1183
|
-
- If a tool does not exist in the list, it does not exist, DO NOT INVENT tools
|
|
1184
|
-
|
|
1185
|
-
AGENT-SPECIFIC TOOLS (Always Available):
|
|
1186
|
-
These tools are provided by the agent itself for event management:
|
|
1187
|
-
All parameters are MANDATORY
|
|
1188
|
-
|
|
1189
|
-
1. studio_agent_subscribeImmediate - Subscribe to events that need immediate action
|
|
1190
|
-
Parameters:
|
|
1191
|
-
- componentId: string (ID of component to subscribe to)
|
|
1192
|
-
- eventType: string (Type of event from listEvents)
|
|
1193
|
-
- cyclePrompt: string (The prompt for the Cycle LLM when this callback is invoked)
|
|
1194
|
-
NOTE: When these events fire, they'll appear in working memory as 'immediate_events'
|
|
1195
|
-
|
|
1196
|
-
2. studio_agent_subscribeAggregated - Subscribe to high-frequency events for batch analysis
|
|
1197
|
-
Parameters:
|
|
1198
|
-
- subscriptionId: string (Unique ID for this subscription group)
|
|
1199
|
-
- sources: Array<{componentId: string, eventType: string, fieldPath?: string}> (Events to aggregate)
|
|
1200
|
-
- windowSeconds: number (How often to analyze, e.g., 10)
|
|
1201
|
-
- retentionSeconds?: number (How much history to keep, defaults to window)
|
|
1202
|
-
- cyclePrompt: string (The prompt for the Cycle LLM when this callback is invoked)
|
|
1203
|
-
- fieldPath: string (Optional dot notation path like "levels.rms" to extract specific data and reduce context bloat)
|
|
1204
|
-
NOTE: Every windowSeconds, aggregated data will appear in working memory under the subscriptionId
|
|
1205
|
-
FIELD EXTRACTION: Use fieldPath to extract specific data like "levels.rms" from audio level events
|
|
1206
|
-
|
|
1207
|
-
3. studio_agent_unsubscribe - Remove an event subscription
|
|
1208
|
-
Parameters:
|
|
1209
|
-
- subscriptionId: string (ID to unsubscribe)
|
|
1210
|
-
|
|
1211
|
-
4. studio_agent_setTimer - Set a timer that triggers after specified seconds
|
|
1212
|
-
Parameters:
|
|
1213
|
-
- timerId: string (Unique ID for this timer)
|
|
1214
|
-
- delaySeconds: number (How many seconds until timer fires)
|
|
1215
|
-
- cyclePrompt: string (The prompt for the Cycle LLM when this callback is invoked)
|
|
1216
|
-
- recurring?: boolean (If true, timer repeats every delaySeconds)
|
|
1217
|
-
NOTE: When timer fires, it appears in working memory as 'timer_events'
|
|
1218
|
-
|
|
1219
|
-
5. studio_agent_cancelTimer - Cancel an active timer
|
|
1220
|
-
Parameters:
|
|
1221
|
-
- timerId: string (ID of timer to cancel)
|
|
1222
|
-
|
|
1223
|
-
6. studio_agent_listSubscriptions - List all active subscriptions
|
|
1224
|
-
Parameters: none
|
|
1225
|
-
|
|
1226
|
-
AVAILABLE CONTROL METHODS:
|
|
1227
|
-
Many components now support Commands (structured control actions):
|
|
1228
|
-
- Input components: file, WHIP, SRT, RTMP - have play/stop/connect/disconnect commands
|
|
1229
|
-
- Output components: statistics, WHEP, UDP, SRT, RTMP, preview, CMAF, HLS - have enable/disable commands
|
|
1230
|
-
- Processor components: switches, overlays, gates, browser overlay - have state control commands
|
|
1231
|
-
- Use {componentId}_cmd_executeCommand for direct component control
|
|
1232
|
-
- Use {componentId}_executeRoute for control when commands don't exist for a task
|
|
1233
|
-
|
|
1234
|
-
STEP-BY-STEP DISCOVERY (MANDATORY):
|
|
1235
|
-
1. workflow_listComponents - Returns actual component IDs (e.g., "ll-hls", "input-1", etc.)
|
|
1236
|
-
2. {componentId}_cmd_listCommands - Replace {componentId} with ACTUAL ID from step 1 - this returns available command names
|
|
1237
|
-
3. {componentId}_cmd_getCommandSchema - replace {componentId} with ACTUAL ID and provide 'commandName' from step 2 as a parameter, you MUST call this for each relevant command to get schemas, storing these schemas in memory is recommended
|
|
1238
|
-
4. {componentId}_listRoutes - Replace {componentId} with ACTUAL ID from step 1
|
|
1239
|
-
5. {componentId}_getRouteSchema - replace {componentId} with ACTUAL ID from step 1, providing the url AND method from step 4, you MUST call this to get the schema in order to execute a route, storing this schema in memory is recommended
|
|
1240
|
-
6. {componentId}_cmd_executeCommand - Direct command execution (preferred for supported components), ALWAYS conform to the schema gathered in step 3 for the parameters of a command
|
|
1241
|
-
7. {componentId}_executeRoute - Use HTTP routes when commands aren't available, ALWAYS conform to the schema gathered in step 5
|
|
1242
|
-
8. {componentId}_evt_listEvents - Lists all event types the component can emit, replace {componentId} with ACTUAL ID
|
|
1243
|
-
9. {componentId}_evt_getEventSchema - Gets the detailed schema for events, replace {componentId} with ACTUAL ID, and provide the event name from step 8
|
|
1244
|
-
|
|
1245
|
-
IMPORTANT NOTES:
|
|
1246
|
-
- Tool names are now abbreviated for efficiency (e.g., "osc_gfx" = "on_screen_graphic")
|
|
1247
|
-
- ALWAYS read tool descriptions carefully - they contain the full component names and detailed functionality
|
|
1248
|
-
- Store component metadata in memory: original component ID, abbreviated name, type, and capabilities
|
|
1249
|
-
- Use tool descriptions to understand what each abbreviated tool actually does
|
|
1250
|
-
- Pay attention to tool descriptions when choosing between similar tools
|
|
1251
|
-
|
|
1252
|
-
DO NOT SKIP DISCOVERY. DO NOT GUESS TOOL NAMES. READ TOOL DESCRIPTIONS CAREFULLY.
|
|
1253
|
-
`;
|
|
1254
|
-
//# sourceMappingURL=runtime.js.map
|