agent-state-machine 2.1.3 → 2.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-state-machine",
3
- "version": "2.1.3",
3
+ "version": "2.1.5",
4
4
  "type": "module",
5
5
  "description": "A workflow orchestrator for running agents and scripts in sequence with state management",
6
6
  "main": "lib/index.js",
@@ -8,6 +8,5 @@ export const config = {
8
8
  gemini: process.env.GEMINI_API_KEY,
9
9
  anthropic: process.env.ANTHROPIC_API_KEY,
10
10
  openai: process.env.OPENAI_API_KEY,
11
- },
12
- remotePath: "TczrLmUecnqZPpPhBTrvU374CGlfzDfINrr0eN0nMgQ",
11
+ }
13
12
  };
@@ -57,13 +57,13 @@ export default async function handler(req, res) {
57
57
 
58
58
  // Track current position for polling new events
59
59
  let lastEventIndex = await getEventsLength(token);
60
+ let pollCount = 0;
60
61
 
61
62
  const pollInterval = setInterval(async () => {
62
63
  try {
63
- // Refresh session TTL
64
- await refreshSession(token);
64
+ pollCount++;
65
65
 
66
- // Check for new events
66
+ // Check for new events (most important, do this every poll)
67
67
  const newLength = await getEventsLength(token);
68
68
 
69
69
  if (newLength > lastEventIndex) {
@@ -82,18 +82,23 @@ export default async function handler(req, res) {
82
82
  lastEventIndex = newLength;
83
83
  }
84
84
 
85
- // Check CLI status
86
- const updatedSession = await getSession(token);
87
- if (updatedSession && updatedSession.cliConnected !== session.cliConnected) {
88
- session.cliConnected = updatedSession.cliConnected;
89
- res.write(`data: ${JSON.stringify({
90
- type: updatedSession.cliConnected ? 'cli_reconnected' : 'cli_disconnected',
91
- })}\n\n`);
85
+ // Only check CLI status and refresh session every 5th poll (~15 seconds)
86
+ // This reduces Redis calls significantly
87
+ if (pollCount % 5 === 0) {
88
+ await refreshSession(token);
89
+
90
+ const updatedSession = await getSession(token);
91
+ if (updatedSession && updatedSession.cliConnected !== session.cliConnected) {
92
+ session.cliConnected = updatedSession.cliConnected;
93
+ res.write(`data: ${JSON.stringify({
94
+ type: updatedSession.cliConnected ? 'cli_reconnected' : 'cli_disconnected',
95
+ })}\n\n`);
96
+ }
92
97
  }
93
98
  } catch (err) {
94
99
  console.error('Error polling events:', err);
95
100
  }
96
- }, 1000); // Poll every 1 second for faster updates
101
+ }, 3000); // Poll every 3 seconds (was 1 second) - 3x reduction
97
102
 
98
103
  // Clean up on client disconnect
99
104
  req.on('close', () => {
@@ -44,14 +44,16 @@ export default async function handler(req, res) {
44
44
  */
45
45
  async function handlePost(req, res) {
46
46
  const body = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
47
- const { type, sessionToken } = body;
47
+ const { sessionToken } = body;
48
+ // Support both _action (new) and type (legacy) for message routing
49
+ const action = body._action || body.type;
48
50
 
49
51
  if (!sessionToken) {
50
52
  return res.status(400).json({ error: 'Missing sessionToken' });
51
53
  }
52
54
 
53
55
  try {
54
- switch (type) {
56
+ switch (action) {
55
57
  case 'session_init': {
56
58
  const { workflowName, history } = body;
57
59
 
@@ -89,9 +91,9 @@ async function handlePost(req, res) {
89
91
  ...eventData,
90
92
  };
91
93
 
92
- // Remove sessionToken and type from event data
94
+ // Remove routing fields, preserve type (interaction type like 'choice')
93
95
  delete historyEvent.sessionToken;
94
- delete historyEvent.type;
96
+ delete historyEvent._action;
95
97
 
96
98
  // Add to events list (single source of truth)
97
99
  await addEvent(sessionToken, historyEvent);
@@ -125,7 +127,7 @@ async function handlePost(req, res) {
125
127
  }
126
128
 
127
129
  default:
128
- return res.status(400).json({ error: `Unknown message type: ${type}` });
130
+ return res.status(400).json({ error: `Unknown action: ${action}` });
129
131
  }
130
132
  } catch (err) {
131
133
  console.error('Error handling CLI message:', err);
@@ -135,6 +137,7 @@ async function handlePost(req, res) {
135
137
 
136
138
  /**
137
139
  * Handle GET requests - long-poll for interaction responses
140
+ * Uses efficient polling with 5-second intervals (Upstash doesn't support BLPOP)
138
141
  */
139
142
  async function handleGet(req, res) {
140
143
  const { token, timeout = '30000' } = req.query;
@@ -148,16 +151,15 @@ async function handleGet(req, res) {
148
151
  return res.status(404).json({ error: 'Session not found' });
149
152
  }
150
153
 
151
- const timeoutMs = Math.min(parseInt(timeout, 10), 55000); // Max 55s for Vercel
154
+ // Max 50s for Vercel (leave buffer for response)
155
+ const timeoutMs = Math.min(parseInt(timeout, 10), 50000);
152
156
  const channel = KEYS.interactions(token);
153
-
154
- // Check for pending interactions using a list
155
157
  const pendingKey = `${channel}:pending`;
156
158
 
157
159
  try {
158
- // Try to get a pending interaction
159
160
  const startTime = Date.now();
160
161
 
162
+ // Poll every 5 seconds (10 calls per 50s timeout vs 50 calls before)
161
163
  while (Date.now() - startTime < timeoutMs) {
162
164
  const pending = await redis.lpop(pendingKey);
163
165
 
@@ -169,8 +171,8 @@ async function handleGet(req, res) {
169
171
  });
170
172
  }
171
173
 
172
- // Wait before checking again
173
- await new Promise((resolve) => setTimeout(resolve, 1000));
174
+ // Wait 5 seconds before checking again (was 1 second)
175
+ await new Promise((resolve) => setTimeout(resolve, 5000));
174
176
  }
175
177
 
176
178
  // Timeout - no interaction received