@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.
Files changed (103) hide show
  1. package/client/info.js +1630 -1316
  2. package/client/style.css +7 -599
  3. package/lib/info.js +6 -4
  4. package/lib/info.js.map +1 -1
  5. package/lib/processor.objectDetect/_gen/schema.d.ts +12 -0
  6. package/lib/processor.objectDetect/_gen/schema.js +16 -0
  7. package/lib/processor.objectDetect/_gen/schema.js.map +1 -0
  8. package/lib/processor.objectDetect/_gen/types.d.ts +49 -0
  9. package/lib/processor.objectDetect/_gen/types.js.map +1 -0
  10. package/lib/processor.objectDetect/_gen/zod.js +60 -0
  11. package/lib/processor.objectDetect/_gen/zod.js.map +1 -0
  12. package/lib/processor.objectDetect/info.d.ts +27 -0
  13. package/lib/processor.objectDetect/info.js +63 -0
  14. package/lib/processor.objectDetect/info.js.map +1 -0
  15. package/lib/processor.objectDetect/inline-view.d.ts +6 -0
  16. package/lib/processor.objectDetect/inline-view.js +41 -0
  17. package/lib/processor.objectDetect/inline-view.js.map +1 -0
  18. package/lib/processor.objectDetect/runtime.d.ts +28 -0
  19. package/lib/processor.objectDetect/runtime.js +112 -0
  20. package/lib/processor.objectDetect/runtime.js.map +1 -0
  21. package/lib/processor.objectDetect/types.yaml +78 -0
  22. package/lib/test/output.tams.js.map +1 -1
  23. package/lib/util.claudeAgent/_gen/schema.d.ts +17 -0
  24. package/lib/util.claudeAgent/_gen/schema.js +21 -0
  25. package/lib/util.claudeAgent/_gen/schema.js.map +1 -0
  26. package/lib/util.claudeAgent/_gen/types.d.ts +370 -0
  27. package/lib/util.claudeAgent/_gen/types.js.map +1 -0
  28. package/lib/util.claudeAgent/_gen/zod.js +147 -0
  29. package/lib/util.claudeAgent/_gen/zod.js.map +1 -0
  30. package/lib/util.claudeAgent/info.d.ts +63 -0
  31. package/lib/util.claudeAgent/info.js +131 -0
  32. package/lib/util.claudeAgent/info.js.map +1 -0
  33. package/lib/util.claudeAgent/runtime.d.ts +105 -0
  34. package/lib/util.claudeAgent/runtime.js +567 -0
  35. package/lib/util.claudeAgent/runtime.js.map +1 -0
  36. package/lib/util.claudeAgent/types.yaml +393 -0
  37. package/lib/util.geminiAgent/_gen/schema.d.ts +17 -0
  38. package/lib/util.geminiAgent/_gen/schema.js +21 -0
  39. package/lib/util.geminiAgent/_gen/schema.js.map +1 -0
  40. package/lib/util.geminiAgent/_gen/types.d.ts +370 -0
  41. package/lib/util.geminiAgent/_gen/types.js.map +1 -0
  42. package/lib/util.geminiAgent/_gen/zod.d.ts +2 -0
  43. package/lib/util.geminiAgent/_gen/zod.js +147 -0
  44. package/lib/util.geminiAgent/_gen/zod.js.map +1 -0
  45. package/lib/util.geminiAgent/info.d.ts +63 -0
  46. package/lib/util.geminiAgent/info.js +131 -0
  47. package/lib/util.geminiAgent/info.js.map +1 -0
  48. package/lib/util.geminiAgent/runtime.d.ts +107 -0
  49. package/lib/util.geminiAgent/runtime.js +621 -0
  50. package/lib/util.geminiAgent/runtime.js.map +1 -0
  51. package/lib/util.geminiAgent/types.yaml +392 -0
  52. package/package.json +24 -5
  53. package/client/util.aiChat/styles.css +0 -371
  54. package/lib/util.agent/_gen/schema.d.ts +0 -13
  55. package/lib/util.agent/_gen/schema.js +0 -17
  56. package/lib/util.agent/_gen/schema.js.map +0 -1
  57. package/lib/util.agent/_gen/types.d.ts +0 -343
  58. package/lib/util.agent/_gen/types.js.map +0 -1
  59. package/lib/util.agent/_gen/zod.js +0 -206
  60. package/lib/util.agent/_gen/zod.js.map +0 -1
  61. package/lib/util.agent/fullscreen-view.d.ts +0 -4
  62. package/lib/util.agent/fullscreen-view.js +0 -142
  63. package/lib/util.agent/fullscreen-view.js.map +0 -1
  64. package/lib/util.agent/info.d.ts +0 -126
  65. package/lib/util.agent/info.js +0 -141
  66. package/lib/util.agent/info.js.map +0 -1
  67. package/lib/util.agent/inline-view.d.ts +0 -6
  68. package/lib/util.agent/inline-view.js +0 -43
  69. package/lib/util.agent/inline-view.js.map +0 -1
  70. package/lib/util.agent/runtime.d.ts +0 -180
  71. package/lib/util.agent/runtime.js +0 -1254
  72. package/lib/util.agent/runtime.js.map +0 -1
  73. package/lib/util.agent/summary-view.d.ts +0 -4
  74. package/lib/util.agent/summary-view.js +0 -68
  75. package/lib/util.agent/summary-view.js.map +0 -1
  76. package/lib/util.agent/types.d.ts +0 -285
  77. package/lib/util.agent/types.js.map +0 -1
  78. package/lib/util.agent/types.yaml +0 -440
  79. package/lib/util.aiChat/_gen/schema.d.ts +0 -12
  80. package/lib/util.aiChat/_gen/schema.js +0 -16
  81. package/lib/util.aiChat/_gen/schema.js.map +0 -1
  82. package/lib/util.aiChat/_gen/types.d.ts +0 -98
  83. package/lib/util.aiChat/_gen/types.js.map +0 -1
  84. package/lib/util.aiChat/_gen/zod.js +0 -132
  85. package/lib/util.aiChat/_gen/zod.js.map +0 -1
  86. package/lib/util.aiChat/info.d.ts +0 -70
  87. package/lib/util.aiChat/info.js +0 -92
  88. package/lib/util.aiChat/info.js.map +0 -1
  89. package/lib/util.aiChat/runtime.d.ts +0 -32
  90. package/lib/util.aiChat/runtime.js +0 -304
  91. package/lib/util.aiChat/runtime.js.map +0 -1
  92. package/lib/util.aiChat/summary-view.d.ts +0 -7
  93. package/lib/util.aiChat/summary-view.js +0 -48
  94. package/lib/util.aiChat/summary-view.js.map +0 -1
  95. package/lib/util.aiChat/types.d.ts +0 -62
  96. package/lib/util.aiChat/types.js +0 -3
  97. package/lib/util.aiChat/types.js.map +0 -1
  98. package/lib/util.aiChat/types.yaml +0 -148
  99. /package/lib/{util.agent → processor.objectDetect}/_gen/types.js +0 -0
  100. /package/lib/{util.agent → processor.objectDetect}/_gen/zod.d.ts +0 -0
  101. /package/lib/{util.agent → util.claudeAgent/_gen}/types.js +0 -0
  102. /package/lib/{util.aiChat → util.claudeAgent}/_gen/zod.d.ts +0 -0
  103. /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