@norskvideo/norsk-studio-alpha 1.27.0-2025-10-09-e06493b0 → 1.27.0-2025-10-12-efe33298

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