agentgui 1.0.110 → 1.0.111
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/.prd +281 -0
- package/database.js +87 -0
- package/package.json +2 -2
- package/server.js +25 -2
- package/static/index.html +48 -0
- package/static/js/client.js +14 -7
- package/static/js/conversations.js +41 -2
- package/conversation-importer.js +0 -63
- package/hot-reload-manager.js +0 -186
- package/lib/database-service.ts +0 -640
- package/lib/machines.ts +0 -190
- package/lib/schemas.ts +0 -190
- package/lib/sync-service.ts +0 -615
- package/lib/types.ts +0 -413
package/lib/machines.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MACHINES.TS - XState state machines for conversations and sync
|
|
3
|
-
* Guarantees valid state transitions and explicit error recovery
|
|
4
|
-
* All possible paths tested and verified
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { createMachine, assign, actions } from 'xstate';
|
|
8
|
-
import { SyncMachineContext, SyncState, ConversationStatus } from './types';
|
|
9
|
-
|
|
10
|
-
const { send } = actions;
|
|
11
|
-
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// CONVERSATION SYNC STATE MACHINE
|
|
14
|
-
// ============================================================================
|
|
15
|
-
|
|
16
|
-
export const conversationSyncMachine = createMachine(
|
|
17
|
-
{
|
|
18
|
-
id: 'conversationSync',
|
|
19
|
-
initial: 'idle',
|
|
20
|
-
context: {
|
|
21
|
-
conversationId: undefined,
|
|
22
|
-
messageId: undefined,
|
|
23
|
-
lastError: undefined,
|
|
24
|
-
retryCount: 0,
|
|
25
|
-
syncData: {},
|
|
26
|
-
},
|
|
27
|
-
states: {
|
|
28
|
-
// IDLE: Waiting for work
|
|
29
|
-
idle: {
|
|
30
|
-
on: {
|
|
31
|
-
LOAD_CONVERSATIONS: {
|
|
32
|
-
target: 'loading',
|
|
33
|
-
actions: assign({
|
|
34
|
-
retryCount: 0,
|
|
35
|
-
lastError: undefined,
|
|
36
|
-
}),
|
|
37
|
-
},
|
|
38
|
-
SYNC_CONVERSATIONS: {
|
|
39
|
-
target: 'syncing',
|
|
40
|
-
actions: assign({
|
|
41
|
-
retryCount: 0,
|
|
42
|
-
lastError: undefined,
|
|
43
|
-
}),
|
|
44
|
-
},
|
|
45
|
-
OFFLINE: 'offline',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
// LOADING: Initial load of conversations
|
|
50
|
-
loading: {
|
|
51
|
-
on: {
|
|
52
|
-
LOAD_SUCCESS: {
|
|
53
|
-
target: 'synced',
|
|
54
|
-
actions: assign({
|
|
55
|
-
syncData: (context, event: any) => event.data,
|
|
56
|
-
}),
|
|
57
|
-
},
|
|
58
|
-
LOAD_ERROR: {
|
|
59
|
-
target: 'error',
|
|
60
|
-
actions: assign({
|
|
61
|
-
lastError: (context, event: any) => event.error,
|
|
62
|
-
}),
|
|
63
|
-
},
|
|
64
|
-
OFFLINE: 'offline',
|
|
65
|
-
},
|
|
66
|
-
after: {
|
|
67
|
-
30000: { // 30 second timeout
|
|
68
|
-
target: 'error',
|
|
69
|
-
actions: assign({
|
|
70
|
-
lastError: new Error('Load timeout (30s)'),
|
|
71
|
-
}),
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
|
|
76
|
-
// SYNCING: Active sync operation
|
|
77
|
-
syncing: {
|
|
78
|
-
on: {
|
|
79
|
-
SYNC_SUCCESS: {
|
|
80
|
-
target: 'synced',
|
|
81
|
-
actions: assign({
|
|
82
|
-
syncData: (context, event: any) => event.data,
|
|
83
|
-
}),
|
|
84
|
-
},
|
|
85
|
-
SYNC_ERROR: {
|
|
86
|
-
target: 'error',
|
|
87
|
-
actions: assign({
|
|
88
|
-
lastError: (context, event: any) => event.error,
|
|
89
|
-
retryCount: (context) => context.retryCount + 1,
|
|
90
|
-
}),
|
|
91
|
-
},
|
|
92
|
-
OFFLINE: 'offline',
|
|
93
|
-
},
|
|
94
|
-
after: {
|
|
95
|
-
60000: { // 60 second timeout
|
|
96
|
-
target: 'error',
|
|
97
|
-
actions: assign({
|
|
98
|
-
lastError: new Error('Sync timeout (60s)'),
|
|
99
|
-
}),
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
// SYNCED: Data is current
|
|
105
|
-
synced: {
|
|
106
|
-
on: {
|
|
107
|
-
CHANGE_DETECTED: 'syncing',
|
|
108
|
-
OFFLINE: 'offline',
|
|
109
|
-
REFRESH: 'loading',
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
// ERROR: Sync failed
|
|
114
|
-
error: {
|
|
115
|
-
on: {
|
|
116
|
-
RETRY: {
|
|
117
|
-
target: 'syncing',
|
|
118
|
-
cond: (context) => context.retryCount < 5,
|
|
119
|
-
actions: assign({
|
|
120
|
-
retryCount: (context) => context.retryCount + 1,
|
|
121
|
-
}),
|
|
122
|
-
},
|
|
123
|
-
MANUAL_RETRY: {
|
|
124
|
-
target: 'syncing',
|
|
125
|
-
actions: assign({
|
|
126
|
-
retryCount: 0,
|
|
127
|
-
}),
|
|
128
|
-
},
|
|
129
|
-
OFFLINE: 'offline',
|
|
130
|
-
RESET: 'idle',
|
|
131
|
-
},
|
|
132
|
-
after: {
|
|
133
|
-
// Exponential backoff: 1s, 2s, 4s, 8s, 16s
|
|
134
|
-
[Math.min(1000 * Math.pow(2, 0), 16000)]: {
|
|
135
|
-
target: 'syncing',
|
|
136
|
-
cond: (context) => context.retryCount < 5,
|
|
137
|
-
actions: assign({
|
|
138
|
-
retryCount: (context) => context.retryCount + 1,
|
|
139
|
-
}),
|
|
140
|
-
},
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
// OFFLINE: Network unavailable
|
|
145
|
-
offline: {
|
|
146
|
-
on: {
|
|
147
|
-
ONLINE: {
|
|
148
|
-
target: 'loading',
|
|
149
|
-
actions: assign({
|
|
150
|
-
retryCount: 0,
|
|
151
|
-
}),
|
|
152
|
-
},
|
|
153
|
-
RESET: 'idle',
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
|
|
157
|
-
// RECONCILING: Merging local and remote changes
|
|
158
|
-
reconciling: {
|
|
159
|
-
on: {
|
|
160
|
-
RECONCILE_SUCCESS: 'synced',
|
|
161
|
-
RECONCILE_FAILED: 'error',
|
|
162
|
-
OFFLINE: 'offline',
|
|
163
|
-
},
|
|
164
|
-
after: {
|
|
165
|
-
5000: {
|
|
166
|
-
target: 'error',
|
|
167
|
-
actions: assign({
|
|
168
|
-
lastError: new Error('Reconciliation timeout (5s)'),
|
|
169
|
-
}),
|
|
170
|
-
},
|
|
171
|
-
},
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
guards: {
|
|
177
|
-
canRetry: (context) => context.retryCount < 5,
|
|
178
|
-
},
|
|
179
|
-
actions: {
|
|
180
|
-
logError: (context, event) => {
|
|
181
|
-
console.error('[ConversationSync] Error:', (event as any).error?.message);
|
|
182
|
-
},
|
|
183
|
-
logRetry: (context) => {
|
|
184
|
-
const delay = Math.min(1000 * Math.pow(2, context.retryCount), 16000);
|
|
185
|
-
console.log(`[ConversationSync] Retrying in ${delay}ms (attempt ${context.retryCount + 1}/5)`);
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
}
|
|
189
|
-
);
|
|
190
|
-
|
package/lib/schemas.ts
DELETED
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SCHEMAS.TS - Zod validation schemas for all data structures
|
|
3
|
-
* Ensures data integrity at every boundary (API, database, client)
|
|
4
|
-
* Provides type-safe parsing and validation
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
|
|
9
|
-
// ============================================================================
|
|
10
|
-
// CONVERSATION SCHEMAS
|
|
11
|
-
// ============================================================================
|
|
12
|
-
|
|
13
|
-
export const ConversationStatusSchema = z.enum(['active', 'archived', 'deleted']);
|
|
14
|
-
|
|
15
|
-
export const ConversationSchema = z.object({
|
|
16
|
-
id: z.string().min(1),
|
|
17
|
-
agentId: z.string().min(1),
|
|
18
|
-
title: z.string().nullable().optional(),
|
|
19
|
-
created_at: z.number().int().positive(),
|
|
20
|
-
updated_at: z.number().int().positive(),
|
|
21
|
-
status: ConversationStatusSchema,
|
|
22
|
-
agentType: z.string().optional(),
|
|
23
|
-
source: z.enum(['gui', 'imported']).optional(),
|
|
24
|
-
externalId: z.string().optional(),
|
|
25
|
-
firstPrompt: z.string().optional(),
|
|
26
|
-
messageCount: z.number().int().nonnegative().optional(),
|
|
27
|
-
projectPath: z.string().optional(),
|
|
28
|
-
gitBranch: z.string().optional(),
|
|
29
|
-
sourcePath: z.string().optional(),
|
|
30
|
-
lastSyncedAt: z.number().int().optional(),
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
export const ConversationCreateInputSchema = z.object({
|
|
34
|
-
agentId: z.string().min(1, 'agentId is required'),
|
|
35
|
-
title: z.string().max(500).nullable().optional(),
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
export const ConversationUpdateInputSchema = z.object({
|
|
39
|
-
title: z.string().max(500).optional(),
|
|
40
|
-
status: ConversationStatusSchema.optional(),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
export const ConversationsListSchema = z.object({
|
|
44
|
-
conversations: z.array(ConversationSchema),
|
|
45
|
-
total: z.number().int().nonnegative(),
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// ============================================================================
|
|
49
|
-
// MESSAGE SCHEMAS
|
|
50
|
-
// ============================================================================
|
|
51
|
-
|
|
52
|
-
export const MessageRoleSchema = z.enum(['user', 'assistant', 'system']);
|
|
53
|
-
|
|
54
|
-
export const MessageSchema = z.object({
|
|
55
|
-
id: z.string().min(1),
|
|
56
|
-
conversationId: z.string().min(1),
|
|
57
|
-
role: MessageRoleSchema,
|
|
58
|
-
content: z.string(),
|
|
59
|
-
created_at: z.number().int().positive(),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export const MessageCreateInputSchema = z.object({
|
|
63
|
-
conversationId: z.string().min(1),
|
|
64
|
-
role: MessageRoleSchema,
|
|
65
|
-
content: z.string().min(1, 'content cannot be empty').max(1000000),
|
|
66
|
-
idempotencyKey: z.string().optional(),
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
export const MessagesListSchema = z.object({
|
|
70
|
-
messages: z.array(MessageSchema),
|
|
71
|
-
total: z.number().int().nonnegative(),
|
|
72
|
-
hasMore: z.boolean(),
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
// ============================================================================
|
|
76
|
-
// SESSION SCHEMAS
|
|
77
|
-
// ============================================================================
|
|
78
|
-
|
|
79
|
-
export const SessionStatusSchema = z.enum(['pending', 'processing', 'completed', 'error', 'cancelled']);
|
|
80
|
-
|
|
81
|
-
export const SessionResponseSchema = z.object({
|
|
82
|
-
text: z.string(),
|
|
83
|
-
messageId: z.string().min(1),
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
export const SessionSchema = z.object({
|
|
87
|
-
id: z.string().min(1),
|
|
88
|
-
conversationId: z.string().min(1),
|
|
89
|
-
status: SessionStatusSchema,
|
|
90
|
-
started_at: z.number().int().positive(),
|
|
91
|
-
completed_at: z.number().int().positive().optional(),
|
|
92
|
-
response: SessionResponseSchema.optional(),
|
|
93
|
-
error: z.string().optional(),
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// ============================================================================
|
|
97
|
-
// SYNC STATE SCHEMAS
|
|
98
|
-
// ============================================================================
|
|
99
|
-
|
|
100
|
-
export const SyncStateSchema = z.enum(['idle', 'loading', 'synced', 'error', 'offline', 'reconciling']);
|
|
101
|
-
|
|
102
|
-
export const SyncStatusSchema = z.object({
|
|
103
|
-
state: SyncStateSchema,
|
|
104
|
-
lastSyncTime: z.number().int().optional(),
|
|
105
|
-
nextRetryTime: z.number().int().optional(),
|
|
106
|
-
error: z.string().optional(),
|
|
107
|
-
retryCount: z.number().int().nonnegative(),
|
|
108
|
-
maxRetries: z.number().int().positive(),
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
export const SyncEventTypeSchema = z.enum([
|
|
112
|
-
'conversation_created',
|
|
113
|
-
'conversation_updated',
|
|
114
|
-
'conversation_deleted',
|
|
115
|
-
'message_created',
|
|
116
|
-
'message_updated',
|
|
117
|
-
'message_deleted',
|
|
118
|
-
'sync_started',
|
|
119
|
-
'sync_completed',
|
|
120
|
-
'sync_failed',
|
|
121
|
-
'offline_detected',
|
|
122
|
-
'online_detected',
|
|
123
|
-
]);
|
|
124
|
-
|
|
125
|
-
export const SyncEventSchema = z.object({
|
|
126
|
-
type: SyncEventTypeSchema,
|
|
127
|
-
timestamp: z.number().int().positive(),
|
|
128
|
-
data: z.record(z.unknown()),
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// ============================================================================
|
|
132
|
-
// PAGINATION SCHEMAS
|
|
133
|
-
// ============================================================================
|
|
134
|
-
|
|
135
|
-
export const PaginationParamsSchema = z.object({
|
|
136
|
-
limit: z.number().int().positive().max(100),
|
|
137
|
-
offset: z.number().int().nonnegative(),
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
export const PaginatedResultSchema = <T extends z.ZodTypeAny>(itemSchema: T) =>
|
|
141
|
-
z.object({
|
|
142
|
-
items: z.array(itemSchema),
|
|
143
|
-
total: z.number().int().nonnegative(),
|
|
144
|
-
limit: z.number().int().positive(),
|
|
145
|
-
offset: z.number().int().nonnegative(),
|
|
146
|
-
hasMore: z.boolean(),
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
// ============================================================================
|
|
150
|
-
// IDEMPOTENCY SCHEMAS
|
|
151
|
-
// ============================================================================
|
|
152
|
-
|
|
153
|
-
export const IdempotencyKeySchema = z.object({
|
|
154
|
-
key: z.string().min(1),
|
|
155
|
-
value: z.string(),
|
|
156
|
-
created_at: z.number().int().positive(),
|
|
157
|
-
ttl: z.number().int().positive(),
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// ============================================================================
|
|
161
|
-
// API RESPONSE SCHEMAS
|
|
162
|
-
// ============================================================================
|
|
163
|
-
|
|
164
|
-
export const ApiResponseSchema = <T extends z.ZodTypeAny>(dataSchema: T) =>
|
|
165
|
-
z.object({
|
|
166
|
-
data: dataSchema.optional(),
|
|
167
|
-
error: z.string().optional(),
|
|
168
|
-
timestamp: z.number().int().positive(),
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// ============================================================================
|
|
172
|
-
// VALIDATION HELPER FUNCTIONS
|
|
173
|
-
// ============================================================================
|
|
174
|
-
|
|
175
|
-
export function validateConversation(data: unknown) {
|
|
176
|
-
try {
|
|
177
|
-
return { valid: true, data: ConversationSchema.parse(data) };
|
|
178
|
-
} catch (error) {
|
|
179
|
-
return { valid: false, error: String(error) };
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
export function validateMessage(data: unknown) {
|
|
184
|
-
try {
|
|
185
|
-
return { valid: true, data: MessageSchema.parse(data) };
|
|
186
|
-
} catch (error) {
|
|
187
|
-
return { valid: false, error: String(error) };
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|