pybao-xc-sdk 1.5.51
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/README.md +145 -0
- package/dist/index.d.mts +3264 -0
- package/dist/index.d.ts +3264 -0
- package/dist/index.js +2423 -0
- package/dist/index.mjs +2308 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2423 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
BackendKindSchema: () => BackendKindSchema,
|
|
24
|
+
ContentBlockSchema: () => ContentBlockSchema,
|
|
25
|
+
DEFAULT_SESSION_BACKEND_ROUTER_CONFIG: () => DEFAULT_SESSION_BACKEND_ROUTER_CONFIG,
|
|
26
|
+
DualTrackMetricsSchema: () => DualTrackMetricsSchema,
|
|
27
|
+
DualTrackRawStatsSchema: () => DualTrackRawStatsSchema,
|
|
28
|
+
DualTrackThresholdsSchema: () => DualTrackThresholdsSchema,
|
|
29
|
+
ErrorEventSchema: () => ErrorEventSchema,
|
|
30
|
+
ErrorStreamEventSchema: () => ErrorStreamEventSchema,
|
|
31
|
+
FALLBACK_TRIGGER_MATRIX: () => FALLBACK_TRIGGER_MATRIX,
|
|
32
|
+
FallbackTriggerReasonSchema: () => FallbackTriggerReasonSchema,
|
|
33
|
+
MessageCompletedEventSchema: () => MessageCompletedEventSchema,
|
|
34
|
+
MessageCreatedEventSchema: () => MessageCreatedEventSchema,
|
|
35
|
+
MessageSchema: () => MessageSchema,
|
|
36
|
+
MessageUpdatedEventSchema: () => MessageUpdatedEventSchema,
|
|
37
|
+
PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE: () => PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE,
|
|
38
|
+
PermissionRequestedEventSchema: () => PermissionRequestedEventSchema,
|
|
39
|
+
PermissionRespondedEventSchema: () => PermissionRespondedEventSchema,
|
|
40
|
+
PermissionTimeoutEventSchema: () => PermissionTimeoutEventSchema,
|
|
41
|
+
ProtocolErrorCodeSchema: () => ProtocolErrorCodeSchema,
|
|
42
|
+
ProtocolErrorMappingSchema: () => ProtocolErrorMappingSchema,
|
|
43
|
+
ProtocolSessionStreamBindingManager: () => ProtocolSessionStreamBindingManager,
|
|
44
|
+
PybClient: () => PybClient,
|
|
45
|
+
PybSSEEventSchema: () => PybSSEEventSchema,
|
|
46
|
+
RequestCompletedEventSchema: () => RequestCompletedEventSchema,
|
|
47
|
+
RequestStartedEventSchema: () => RequestStartedEventSchema,
|
|
48
|
+
RuntimeEventDomainSchema: () => RuntimeEventDomainSchema,
|
|
49
|
+
RuntimeEventErrorTypeSchema: () => RuntimeEventErrorTypeSchema,
|
|
50
|
+
RuntimeEventSchema: () => RuntimeEventSchema,
|
|
51
|
+
RuntimeSessionEventSchema: () => RuntimeSessionEventSchema,
|
|
52
|
+
RuntimeSessionInputSchema: () => RuntimeSessionInputSchema,
|
|
53
|
+
RuntimeSessionStatusSchema: () => RuntimeSessionStatusSchema,
|
|
54
|
+
S4_PROTOCOL_ERROR_TOP_CODES: () => S4_PROTOCOL_ERROR_TOP_CODES,
|
|
55
|
+
S5_A0_EQUIVALENCE_SAMPLE_SET: () => S5_A0_EQUIVALENCE_SAMPLE_SET,
|
|
56
|
+
SDK_VERSION: () => SDK_VERSION,
|
|
57
|
+
SESSION_BACKEND_CONFIG_CONTRACT_VERSION: () => SESSION_BACKEND_CONFIG_CONTRACT_VERSION,
|
|
58
|
+
SESSION_BACKEND_ENV_KEY: () => SESSION_BACKEND_ENV_KEY,
|
|
59
|
+
SESSION_BACKEND_OBSERVABILITY_SPEC: () => SESSION_BACKEND_OBSERVABILITY_SPEC,
|
|
60
|
+
SSEClient: () => SSEClient,
|
|
61
|
+
SSEDedupEventSchema: () => SSEDedupEventSchema,
|
|
62
|
+
SSEReplayEventSchema: () => SSEReplayEventSchema,
|
|
63
|
+
SSEReplayGapEventSchema: () => SSEReplayGapEventSchema,
|
|
64
|
+
ServerConnectedEventSchema: () => ServerConnectedEventSchema,
|
|
65
|
+
ServerHeartbeatEventSchema: () => ServerHeartbeatEventSchema,
|
|
66
|
+
ServerStatusEventSchema: () => ServerStatusEventSchema,
|
|
67
|
+
SessionBackendRouterConfigSchema: () => SessionBackendRouterConfigSchema,
|
|
68
|
+
SessionCreatedEventSchema: () => SessionCreatedEventSchema,
|
|
69
|
+
SessionDeletedEventSchema: () => SessionDeletedEventSchema,
|
|
70
|
+
SessionUpdatedEventSchema: () => SessionUpdatedEventSchema,
|
|
71
|
+
ToolCompletedEventSchema: () => ToolCompletedEventSchema,
|
|
72
|
+
ToolErrorEventSchema: () => ToolErrorEventSchema,
|
|
73
|
+
ToolProgressEventSchema: () => ToolProgressEventSchema,
|
|
74
|
+
ToolStartedEventSchema: () => ToolStartedEventSchema,
|
|
75
|
+
V2MessageSchema: () => V2MessageSchema,
|
|
76
|
+
V2RequestStatusSchema: () => V2RequestStatusSchema,
|
|
77
|
+
V2SessionSchema: () => V2SessionSchema,
|
|
78
|
+
V2SessionStatusSchema: () => V2SessionStatusSchema,
|
|
79
|
+
V2ToolUseContextSchema: () => V2ToolUseContextSchema,
|
|
80
|
+
buildDefaultDualTrackThresholds: () => buildDefaultDualTrackThresholds,
|
|
81
|
+
buildV2ToolUseContextFromPromptRequest: () => buildV2ToolUseContextFromPromptRequest,
|
|
82
|
+
canTransitionV2SessionStatus: () => canTransitionV2SessionStatus,
|
|
83
|
+
createDefaultToolPermissionContextForSdk: () => createDefaultToolPermissionContextForSdk,
|
|
84
|
+
createProtocolSessionBackend: () => createProtocolSessionBackend,
|
|
85
|
+
createRuntimePermissionContextForSession: () => createRuntimePermissionContextForSession,
|
|
86
|
+
createRuntimeSession: () => createRuntimeSession,
|
|
87
|
+
createRuntimeSessionBackend: () => createRuntimeSessionBackend,
|
|
88
|
+
createSSEClient: () => createSSEClient,
|
|
89
|
+
createSessionBackendRouter: () => createSessionBackendRouter,
|
|
90
|
+
emitBackendConfigWarning: () => emitBackendConfigWarning,
|
|
91
|
+
evaluateDualTrackMetrics: () => evaluateDualTrackMetrics,
|
|
92
|
+
evaluateV1DeprecationReadiness: () => evaluateV1DeprecationReadiness,
|
|
93
|
+
getRuntimeEventMappingRules: () => getRuntimeEventMappingRules,
|
|
94
|
+
isToolAutoExecutableInContext: () => isToolAutoExecutableInContext,
|
|
95
|
+
mapProtocolErrorCodeToRuntimeErrorType: () => mapProtocolErrorCodeToRuntimeErrorType,
|
|
96
|
+
mapRuntimeBackendErrorToRuntimeEvent: () => mapRuntimeBackendErrorToRuntimeEvent,
|
|
97
|
+
mapRuntimeMessageToV2: () => mapRuntimeMessageToV2,
|
|
98
|
+
mapRuntimeSessionStatusToV2: () => mapRuntimeSessionStatusToV2,
|
|
99
|
+
mapV1MessageToV2: () => mapV1MessageToV2,
|
|
100
|
+
mapV1SessionStatusToV2: () => mapV1SessionStatusToV2,
|
|
101
|
+
projectLegacyEventToRuntimeEvent: () => projectLegacyEventToRuntimeEvent,
|
|
102
|
+
projectRuntimeEventToLegacyEvent: () => projectRuntimeEventToLegacyEvent,
|
|
103
|
+
resolveDefaultBackend: () => resolveDefaultBackend,
|
|
104
|
+
resolveDefaultBackendFromEnv: () => resolveDefaultBackendFromEnv,
|
|
105
|
+
resolvePermissionDecision: () => resolvePermissionDecision,
|
|
106
|
+
resolvePermissionModeForSdk: () => resolvePermissionModeForSdk,
|
|
107
|
+
resolveRouterBackendKind: () => resolveRouterBackendKind,
|
|
108
|
+
shouldTriggerFallback: () => shouldTriggerFallback,
|
|
109
|
+
validateV2Message: () => validateV2Message,
|
|
110
|
+
validateV2Session: () => validateV2Session,
|
|
111
|
+
validateV2ToolUseContext: () => validateV2ToolUseContext
|
|
112
|
+
});
|
|
113
|
+
module.exports = __toCommonJS(index_exports);
|
|
114
|
+
|
|
115
|
+
// src/types.ts
|
|
116
|
+
var import_zod = require("zod");
|
|
117
|
+
var ServerConnectedEventSchema = import_zod.z.object({
|
|
118
|
+
type: import_zod.z.literal("server.connected"),
|
|
119
|
+
timestamp: import_zod.z.number(),
|
|
120
|
+
data: import_zod.z.object({
|
|
121
|
+
serverVersion: import_zod.z.string(),
|
|
122
|
+
protocolVersion: import_zod.z.string(),
|
|
123
|
+
features: import_zod.z.array(import_zod.z.string())
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
var ServerHeartbeatEventSchema = import_zod.z.object({
|
|
127
|
+
type: import_zod.z.literal("server.heartbeat"),
|
|
128
|
+
timestamp: import_zod.z.number(),
|
|
129
|
+
data: import_zod.z.object({
|
|
130
|
+
timestamp: import_zod.z.number()
|
|
131
|
+
})
|
|
132
|
+
});
|
|
133
|
+
var ServerStatusEventSchema = import_zod.z.object({
|
|
134
|
+
type: import_zod.z.literal("server.status"),
|
|
135
|
+
timestamp: import_zod.z.number(),
|
|
136
|
+
data: import_zod.z.object({
|
|
137
|
+
status: import_zod.z.enum(["healthy", "degraded", "unhealthy"]),
|
|
138
|
+
components: import_zod.z.object({
|
|
139
|
+
llm: import_zod.z.enum(["connected", "disconnected"]),
|
|
140
|
+
mcp: import_zod.z.enum(["connected", "disconnected"]),
|
|
141
|
+
tools: import_zod.z.enum(["ready", "initializing"])
|
|
142
|
+
})
|
|
143
|
+
})
|
|
144
|
+
});
|
|
145
|
+
var SessionCreatedEventSchema = import_zod.z.object({
|
|
146
|
+
type: import_zod.z.literal("session.created"),
|
|
147
|
+
timestamp: import_zod.z.number(),
|
|
148
|
+
data: import_zod.z.object({
|
|
149
|
+
sessionId: import_zod.z.string(),
|
|
150
|
+
config: import_zod.z.object({
|
|
151
|
+
model: import_zod.z.string(),
|
|
152
|
+
agent: import_zod.z.string(),
|
|
153
|
+
outputStyle: import_zod.z.string()
|
|
154
|
+
}),
|
|
155
|
+
resumedFrom: import_zod.z.string().optional()
|
|
156
|
+
})
|
|
157
|
+
});
|
|
158
|
+
var SessionUpdatedEventSchema = import_zod.z.object({
|
|
159
|
+
type: import_zod.z.literal("session.updated"),
|
|
160
|
+
timestamp: import_zod.z.number(),
|
|
161
|
+
sessionId: import_zod.z.string(),
|
|
162
|
+
data: import_zod.z.object({
|
|
163
|
+
title: import_zod.z.string().optional(),
|
|
164
|
+
config: import_zod.z.object({
|
|
165
|
+
model: import_zod.z.string().optional(),
|
|
166
|
+
agent: import_zod.z.string().optional(),
|
|
167
|
+
outputStyle: import_zod.z.string().optional()
|
|
168
|
+
}).optional()
|
|
169
|
+
})
|
|
170
|
+
});
|
|
171
|
+
var SessionDeletedEventSchema = import_zod.z.object({
|
|
172
|
+
type: import_zod.z.literal("session.deleted"),
|
|
173
|
+
timestamp: import_zod.z.number(),
|
|
174
|
+
data: import_zod.z.object({
|
|
175
|
+
sessionId: import_zod.z.string()
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
var ContentBlockSchema = import_zod.z.discriminatedUnion("type", [
|
|
179
|
+
import_zod.z.object({ type: import_zod.z.literal("text"), text: import_zod.z.string() }),
|
|
180
|
+
import_zod.z.object({
|
|
181
|
+
type: import_zod.z.literal("tool_use"),
|
|
182
|
+
id: import_zod.z.string(),
|
|
183
|
+
name: import_zod.z.string(),
|
|
184
|
+
input: import_zod.z.record(import_zod.z.unknown())
|
|
185
|
+
}),
|
|
186
|
+
import_zod.z.object({
|
|
187
|
+
type: import_zod.z.literal("tool_result"),
|
|
188
|
+
toolUseId: import_zod.z.string(),
|
|
189
|
+
content: import_zod.z.string(),
|
|
190
|
+
isError: import_zod.z.boolean().optional()
|
|
191
|
+
})
|
|
192
|
+
]);
|
|
193
|
+
var MessageSchema = import_zod.z.object({
|
|
194
|
+
id: import_zod.z.string(),
|
|
195
|
+
role: import_zod.z.enum(["user", "assistant", "system"]),
|
|
196
|
+
content: import_zod.z.union([import_zod.z.string(), import_zod.z.array(ContentBlockSchema)]),
|
|
197
|
+
timestamp: import_zod.z.number(),
|
|
198
|
+
parentId: import_zod.z.string().optional(),
|
|
199
|
+
toolCalls: import_zod.z.array(import_zod.z.object({
|
|
200
|
+
id: import_zod.z.string(),
|
|
201
|
+
name: import_zod.z.string(),
|
|
202
|
+
input: import_zod.z.record(import_zod.z.unknown()),
|
|
203
|
+
status: import_zod.z.enum(["pending", "running", "completed", "error"]).optional(),
|
|
204
|
+
result: import_zod.z.string().optional()
|
|
205
|
+
})).optional(),
|
|
206
|
+
cost: import_zod.z.object({
|
|
207
|
+
inputTokens: import_zod.z.number(),
|
|
208
|
+
outputTokens: import_zod.z.number(),
|
|
209
|
+
costUSD: import_zod.z.number()
|
|
210
|
+
}).optional()
|
|
211
|
+
});
|
|
212
|
+
var MessageCreatedEventSchema = import_zod.z.object({
|
|
213
|
+
type: import_zod.z.literal("message.created"),
|
|
214
|
+
timestamp: import_zod.z.number(),
|
|
215
|
+
sessionId: import_zod.z.string(),
|
|
216
|
+
data: import_zod.z.object({
|
|
217
|
+
message: import_zod.z.unknown()
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
var MessageUpdatedEventSchema = import_zod.z.object({
|
|
221
|
+
type: import_zod.z.literal("message.updated"),
|
|
222
|
+
timestamp: import_zod.z.number(),
|
|
223
|
+
sessionId: import_zod.z.string(),
|
|
224
|
+
data: import_zod.z.object({
|
|
225
|
+
message: import_zod.z.unknown(),
|
|
226
|
+
delta: import_zod.z.object({
|
|
227
|
+
type: import_zod.z.enum(["text", "tool_use"]),
|
|
228
|
+
content: import_zod.z.string(),
|
|
229
|
+
index: import_zod.z.number().optional()
|
|
230
|
+
}).optional()
|
|
231
|
+
})
|
|
232
|
+
});
|
|
233
|
+
var MessageCompletedEventSchema = import_zod.z.object({
|
|
234
|
+
type: import_zod.z.literal("message.completed"),
|
|
235
|
+
timestamp: import_zod.z.number(),
|
|
236
|
+
sessionId: import_zod.z.string(),
|
|
237
|
+
data: import_zod.z.object({
|
|
238
|
+
messageId: import_zod.z.string(),
|
|
239
|
+
finishReason: import_zod.z.enum(["end_turn", "tool_calls", "max_tokens", "aborted"]),
|
|
240
|
+
usage: import_zod.z.object({
|
|
241
|
+
inputTokens: import_zod.z.number(),
|
|
242
|
+
outputTokens: import_zod.z.number(),
|
|
243
|
+
totalTokens: import_zod.z.number()
|
|
244
|
+
}),
|
|
245
|
+
cost: import_zod.z.object({
|
|
246
|
+
costUSD: import_zod.z.number()
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
var RequestStartedEventSchema = import_zod.z.object({
|
|
251
|
+
type: import_zod.z.literal("request.started"),
|
|
252
|
+
timestamp: import_zod.z.number(),
|
|
253
|
+
sessionId: import_zod.z.string(),
|
|
254
|
+
data: import_zod.z.object({
|
|
255
|
+
requestId: import_zod.z.string(),
|
|
256
|
+
userMessage: import_zod.z.string()
|
|
257
|
+
})
|
|
258
|
+
});
|
|
259
|
+
var RequestCompletedEventSchema = import_zod.z.object({
|
|
260
|
+
type: import_zod.z.literal("request.completed"),
|
|
261
|
+
timestamp: import_zod.z.number(),
|
|
262
|
+
sessionId: import_zod.z.string(),
|
|
263
|
+
data: import_zod.z.object({
|
|
264
|
+
requestId: import_zod.z.string(),
|
|
265
|
+
finishReason: import_zod.z.enum(["end_turn", "tool_calls", "max_tokens", "aborted"]),
|
|
266
|
+
duration: import_zod.z.number(),
|
|
267
|
+
totalTokens: import_zod.z.number(),
|
|
268
|
+
costUSD: import_zod.z.number()
|
|
269
|
+
})
|
|
270
|
+
});
|
|
271
|
+
var ToolStartedEventSchema = import_zod.z.object({
|
|
272
|
+
type: import_zod.z.literal("tool.started"),
|
|
273
|
+
timestamp: import_zod.z.number(),
|
|
274
|
+
sessionId: import_zod.z.string(),
|
|
275
|
+
data: import_zod.z.object({
|
|
276
|
+
toolUseId: import_zod.z.string(),
|
|
277
|
+
toolName: import_zod.z.string(),
|
|
278
|
+
input: import_zod.z.record(import_zod.z.unknown()),
|
|
279
|
+
dangerousLevel: import_zod.z.enum(["safe", "moderate", "dangerous"]),
|
|
280
|
+
requiresPermission: import_zod.z.boolean()
|
|
281
|
+
})
|
|
282
|
+
});
|
|
283
|
+
var ToolProgressEventSchema = import_zod.z.object({
|
|
284
|
+
type: import_zod.z.literal("tool.progress"),
|
|
285
|
+
timestamp: import_zod.z.number(),
|
|
286
|
+
sessionId: import_zod.z.string(),
|
|
287
|
+
data: import_zod.z.object({
|
|
288
|
+
toolUseId: import_zod.z.string(),
|
|
289
|
+
toolName: import_zod.z.string(),
|
|
290
|
+
progress: import_zod.z.number().min(0).max(100),
|
|
291
|
+
message: import_zod.z.string().optional(),
|
|
292
|
+
output: import_zod.z.string().optional()
|
|
293
|
+
})
|
|
294
|
+
});
|
|
295
|
+
var ToolCompletedEventSchema = import_zod.z.object({
|
|
296
|
+
type: import_zod.z.literal("tool.completed"),
|
|
297
|
+
timestamp: import_zod.z.number(),
|
|
298
|
+
sessionId: import_zod.z.string(),
|
|
299
|
+
data: import_zod.z.object({
|
|
300
|
+
toolUseId: import_zod.z.string(),
|
|
301
|
+
toolName: import_zod.z.string(),
|
|
302
|
+
result: import_zod.z.string(),
|
|
303
|
+
isError: import_zod.z.boolean(),
|
|
304
|
+
duration: import_zod.z.number()
|
|
305
|
+
})
|
|
306
|
+
});
|
|
307
|
+
var ToolErrorEventSchema = import_zod.z.object({
|
|
308
|
+
type: import_zod.z.literal("tool.error"),
|
|
309
|
+
timestamp: import_zod.z.number(),
|
|
310
|
+
sessionId: import_zod.z.string(),
|
|
311
|
+
data: import_zod.z.object({
|
|
312
|
+
toolUseId: import_zod.z.string(),
|
|
313
|
+
toolName: import_zod.z.string(),
|
|
314
|
+
error: import_zod.z.object({
|
|
315
|
+
code: import_zod.z.string(),
|
|
316
|
+
message: import_zod.z.string(),
|
|
317
|
+
details: import_zod.z.unknown().optional()
|
|
318
|
+
})
|
|
319
|
+
})
|
|
320
|
+
});
|
|
321
|
+
var PermissionRequestedEventSchema = import_zod.z.object({
|
|
322
|
+
type: import_zod.z.literal("permission.requested"),
|
|
323
|
+
timestamp: import_zod.z.number(),
|
|
324
|
+
sessionId: import_zod.z.string(),
|
|
325
|
+
data: import_zod.z.object({
|
|
326
|
+
permissionId: import_zod.z.string(),
|
|
327
|
+
toolName: import_zod.z.string(),
|
|
328
|
+
toolUseId: import_zod.z.string(),
|
|
329
|
+
input: import_zod.z.record(import_zod.z.unknown()),
|
|
330
|
+
risk: import_zod.z.enum(["safe", "moderate", "dangerous"]),
|
|
331
|
+
message: import_zod.z.string(),
|
|
332
|
+
suggestedAction: import_zod.z.enum(["allow", "deny"]).optional(),
|
|
333
|
+
timeout: import_zod.z.number().optional()
|
|
334
|
+
})
|
|
335
|
+
});
|
|
336
|
+
var PermissionRespondedEventSchema = import_zod.z.object({
|
|
337
|
+
type: import_zod.z.literal("permission.responded"),
|
|
338
|
+
timestamp: import_zod.z.number(),
|
|
339
|
+
sessionId: import_zod.z.string(),
|
|
340
|
+
data: import_zod.z.object({
|
|
341
|
+
permissionId: import_zod.z.string(),
|
|
342
|
+
decision: import_zod.z.enum(["allow", "deny", "allowAll"]),
|
|
343
|
+
remember: import_zod.z.boolean(),
|
|
344
|
+
scope: import_zod.z.enum(["session", "project", "global"]).optional()
|
|
345
|
+
})
|
|
346
|
+
});
|
|
347
|
+
var PermissionTimeoutEventSchema = import_zod.z.object({
|
|
348
|
+
type: import_zod.z.literal("permission.timeout"),
|
|
349
|
+
timestamp: import_zod.z.number(),
|
|
350
|
+
sessionId: import_zod.z.string(),
|
|
351
|
+
data: import_zod.z.object({
|
|
352
|
+
permissionId: import_zod.z.string(),
|
|
353
|
+
toolName: import_zod.z.string(),
|
|
354
|
+
defaultAction: import_zod.z.enum(["allow", "deny"])
|
|
355
|
+
})
|
|
356
|
+
});
|
|
357
|
+
var ErrorEventSchema = import_zod.z.object({
|
|
358
|
+
type: import_zod.z.literal("error"),
|
|
359
|
+
timestamp: import_zod.z.number(),
|
|
360
|
+
sessionId: import_zod.z.string().optional(),
|
|
361
|
+
data: import_zod.z.object({
|
|
362
|
+
code: import_zod.z.string(),
|
|
363
|
+
message: import_zod.z.string(),
|
|
364
|
+
details: import_zod.z.unknown().optional(),
|
|
365
|
+
recoverable: import_zod.z.boolean(),
|
|
366
|
+
suggestedAction: import_zod.z.string().optional()
|
|
367
|
+
})
|
|
368
|
+
});
|
|
369
|
+
var ErrorStreamEventSchema = import_zod.z.object({
|
|
370
|
+
type: import_zod.z.literal("error.stream"),
|
|
371
|
+
timestamp: import_zod.z.number(),
|
|
372
|
+
data: import_zod.z.object({
|
|
373
|
+
reason: import_zod.z.enum(["timeout", "aborted", "network", "server"]),
|
|
374
|
+
message: import_zod.z.string(),
|
|
375
|
+
retryable: import_zod.z.boolean(),
|
|
376
|
+
retryAfter: import_zod.z.number().optional()
|
|
377
|
+
})
|
|
378
|
+
});
|
|
379
|
+
var SSEReplayEventSchema = import_zod.z.object({
|
|
380
|
+
type: import_zod.z.literal("sse.replay"),
|
|
381
|
+
timestamp: import_zod.z.number(),
|
|
382
|
+
data: import_zod.z.object({
|
|
383
|
+
replayCount: import_zod.z.number(),
|
|
384
|
+
replayGapCount: import_zod.z.number(),
|
|
385
|
+
lastEventId: import_zod.z.string(),
|
|
386
|
+
firstReplayId: import_zod.z.string().nullable().optional(),
|
|
387
|
+
lastReplayId: import_zod.z.string().nullable().optional()
|
|
388
|
+
})
|
|
389
|
+
});
|
|
390
|
+
var SSEReplayGapEventSchema = import_zod.z.object({
|
|
391
|
+
type: import_zod.z.literal("sse.replay_gap"),
|
|
392
|
+
timestamp: import_zod.z.number(),
|
|
393
|
+
data: import_zod.z.object({
|
|
394
|
+
lastEventId: import_zod.z.string(),
|
|
395
|
+
reason: import_zod.z.enum(["last_event_not_found", "buffer_evicted"])
|
|
396
|
+
})
|
|
397
|
+
});
|
|
398
|
+
var SSEDedupEventSchema = import_zod.z.object({
|
|
399
|
+
type: import_zod.z.literal("sse.dedup"),
|
|
400
|
+
timestamp: import_zod.z.number(),
|
|
401
|
+
data: import_zod.z.object({
|
|
402
|
+
duplicateCount: import_zod.z.number(),
|
|
403
|
+
totalSeen: import_zod.z.number(),
|
|
404
|
+
windowSize: import_zod.z.number()
|
|
405
|
+
})
|
|
406
|
+
});
|
|
407
|
+
var PybSSEEventSchema = import_zod.z.discriminatedUnion("type", [
|
|
408
|
+
ServerConnectedEventSchema,
|
|
409
|
+
ServerHeartbeatEventSchema,
|
|
410
|
+
ServerStatusEventSchema,
|
|
411
|
+
SessionCreatedEventSchema,
|
|
412
|
+
SessionUpdatedEventSchema,
|
|
413
|
+
SessionDeletedEventSchema,
|
|
414
|
+
MessageCreatedEventSchema,
|
|
415
|
+
MessageUpdatedEventSchema,
|
|
416
|
+
MessageCompletedEventSchema,
|
|
417
|
+
RequestStartedEventSchema,
|
|
418
|
+
RequestCompletedEventSchema,
|
|
419
|
+
ToolStartedEventSchema,
|
|
420
|
+
ToolProgressEventSchema,
|
|
421
|
+
ToolCompletedEventSchema,
|
|
422
|
+
ToolErrorEventSchema,
|
|
423
|
+
PermissionRequestedEventSchema,
|
|
424
|
+
PermissionRespondedEventSchema,
|
|
425
|
+
PermissionTimeoutEventSchema,
|
|
426
|
+
ErrorEventSchema,
|
|
427
|
+
ErrorStreamEventSchema,
|
|
428
|
+
SSEReplayEventSchema,
|
|
429
|
+
SSEReplayGapEventSchema,
|
|
430
|
+
SSEDedupEventSchema
|
|
431
|
+
]);
|
|
432
|
+
|
|
433
|
+
// src/client.ts
|
|
434
|
+
var PybClient = class {
|
|
435
|
+
baseUrl;
|
|
436
|
+
timeout;
|
|
437
|
+
headers;
|
|
438
|
+
session;
|
|
439
|
+
mcp;
|
|
440
|
+
tool;
|
|
441
|
+
config;
|
|
442
|
+
constructor(config = {}) {
|
|
443
|
+
this.baseUrl = config.baseUrl ?? "http://localhost:4096/v1";
|
|
444
|
+
this.timeout = config.timeout ?? 12e4;
|
|
445
|
+
this.headers = {
|
|
446
|
+
"Content-Type": "application/json",
|
|
447
|
+
...config.headers
|
|
448
|
+
};
|
|
449
|
+
this.session = {
|
|
450
|
+
create: (request = {}) => this.createSessionRequest(request),
|
|
451
|
+
list: (params) => this.listSessionsRequest(params),
|
|
452
|
+
get: (sessionId) => this.getSessionRequest(sessionId),
|
|
453
|
+
update: (sessionId, updates) => this.updateSessionRequest(sessionId, updates),
|
|
454
|
+
delete: (sessionId) => this.deleteSessionRequest(sessionId),
|
|
455
|
+
prompt: (sessionId, request) => this.sendPromptRequest(sessionId, request),
|
|
456
|
+
abort: (sessionId) => this.abortRequestRequest(sessionId),
|
|
457
|
+
messages: (sessionId, params) => this.getMessagesRequest(sessionId, params)
|
|
458
|
+
};
|
|
459
|
+
this.mcp = {
|
|
460
|
+
list: () => this.listMCPServersRequest(),
|
|
461
|
+
connect: (serverName) => this.connectMCPServerRequest(serverName),
|
|
462
|
+
disconnect: (serverName) => this.disconnectMCPServerRequest(serverName)
|
|
463
|
+
};
|
|
464
|
+
this.tool = {
|
|
465
|
+
list: () => this.listToolsRequest(),
|
|
466
|
+
execute: (toolName, input, options) => this.executeToolRequest(toolName, input, options)
|
|
467
|
+
};
|
|
468
|
+
this.config = {
|
|
469
|
+
get: () => this.getConfigRequest(),
|
|
470
|
+
update: (nextConfig) => this.updateConfigRequest(nextConfig)
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
// ============================================================
|
|
474
|
+
// Health API
|
|
475
|
+
// ============================================================
|
|
476
|
+
async getHealth() {
|
|
477
|
+
const response = await this.fetch("/health");
|
|
478
|
+
return response.json();
|
|
479
|
+
}
|
|
480
|
+
// ============================================================
|
|
481
|
+
// Session API
|
|
482
|
+
// ============================================================
|
|
483
|
+
async createSessionRequest(request = {}) {
|
|
484
|
+
const response = await this.fetch("/sessions", {
|
|
485
|
+
method: "POST",
|
|
486
|
+
body: JSON.stringify(request)
|
|
487
|
+
});
|
|
488
|
+
const result = await response.json();
|
|
489
|
+
return result.data;
|
|
490
|
+
}
|
|
491
|
+
async listSessionsRequest(params) {
|
|
492
|
+
const searchParams = new URLSearchParams();
|
|
493
|
+
if (params?.page) searchParams.set("page", String(params.page));
|
|
494
|
+
if (params?.limit) searchParams.set("limit", String(params.limit));
|
|
495
|
+
if (params?.status) searchParams.set("status", params.status);
|
|
496
|
+
const query = searchParams.toString();
|
|
497
|
+
const response = await this.fetch(`/sessions${query ? `?${query}` : ""}`);
|
|
498
|
+
const result = await response.json();
|
|
499
|
+
return result.data;
|
|
500
|
+
}
|
|
501
|
+
async getSessionRequest(sessionId) {
|
|
502
|
+
const response = await this.fetch(`/sessions/${sessionId}`);
|
|
503
|
+
const result = await response.json();
|
|
504
|
+
return result.data;
|
|
505
|
+
}
|
|
506
|
+
async updateSessionRequest(sessionId, updates) {
|
|
507
|
+
const response = await this.fetch(`/sessions/${sessionId}`, {
|
|
508
|
+
method: "PATCH",
|
|
509
|
+
body: JSON.stringify(updates)
|
|
510
|
+
});
|
|
511
|
+
const result = await response.json();
|
|
512
|
+
return result.data;
|
|
513
|
+
}
|
|
514
|
+
async deleteSessionRequest(sessionId) {
|
|
515
|
+
await this.fetch(`/sessions/${sessionId}`, { method: "DELETE" });
|
|
516
|
+
}
|
|
517
|
+
// ============================================================
|
|
518
|
+
// Message API
|
|
519
|
+
// ============================================================
|
|
520
|
+
async sendPromptRequest(sessionId, request) {
|
|
521
|
+
const response = await this.fetch(`/sessions/${sessionId}/prompt`, {
|
|
522
|
+
method: "POST",
|
|
523
|
+
body: JSON.stringify({ ...request, options: { stream: false, ...request.options } })
|
|
524
|
+
});
|
|
525
|
+
const result = await response.json();
|
|
526
|
+
return result.data;
|
|
527
|
+
}
|
|
528
|
+
async abortRequestRequest(sessionId) {
|
|
529
|
+
const response = await this.fetch(`/sessions/${sessionId}/abort`, {
|
|
530
|
+
method: "POST"
|
|
531
|
+
});
|
|
532
|
+
const result = await response.json();
|
|
533
|
+
return result.data;
|
|
534
|
+
}
|
|
535
|
+
async getMessagesRequest(sessionId, params) {
|
|
536
|
+
const searchParams = new URLSearchParams();
|
|
537
|
+
if (params?.after) searchParams.set("after", params.after);
|
|
538
|
+
if (params?.before) searchParams.set("before", params.before);
|
|
539
|
+
if (params?.limit) searchParams.set("limit", String(params.limit));
|
|
540
|
+
const query = searchParams.toString();
|
|
541
|
+
const response = await this.fetch(`/sessions/${sessionId}/messages${query ? `?${query}` : ""}`);
|
|
542
|
+
const result = await response.json();
|
|
543
|
+
return result.data;
|
|
544
|
+
}
|
|
545
|
+
// ============================================================
|
|
546
|
+
// Permission API
|
|
547
|
+
// ============================================================
|
|
548
|
+
async respondToPermission(permissionId, request) {
|
|
549
|
+
const response = await this.fetch(`/permissions/${permissionId}/respond`, {
|
|
550
|
+
method: "POST",
|
|
551
|
+
body: JSON.stringify(request)
|
|
552
|
+
});
|
|
553
|
+
const result = await response.json();
|
|
554
|
+
return result.data;
|
|
555
|
+
}
|
|
556
|
+
async getPendingPermissions(sessionId) {
|
|
557
|
+
const searchParams = sessionId ? `?sessionId=${sessionId}` : "";
|
|
558
|
+
const response = await this.fetch(`/permissions/pending${searchParams}`);
|
|
559
|
+
const result = await response.json();
|
|
560
|
+
return result.data;
|
|
561
|
+
}
|
|
562
|
+
// ============================================================
|
|
563
|
+
// Tool API
|
|
564
|
+
// ============================================================
|
|
565
|
+
async listToolsRequest() {
|
|
566
|
+
const response = await this.fetch("/tools");
|
|
567
|
+
const result = await response.json();
|
|
568
|
+
return result.data;
|
|
569
|
+
}
|
|
570
|
+
async executeToolRequest(toolName, input, options) {
|
|
571
|
+
const response = await this.fetch(`/tools/${toolName}/execute`, {
|
|
572
|
+
method: "POST",
|
|
573
|
+
body: JSON.stringify({ input, options })
|
|
574
|
+
});
|
|
575
|
+
const result = await response.json();
|
|
576
|
+
return result.data;
|
|
577
|
+
}
|
|
578
|
+
// ============================================================
|
|
579
|
+
// Config API
|
|
580
|
+
// ============================================================
|
|
581
|
+
async getConfigRequest() {
|
|
582
|
+
const response = await this.fetch("/config");
|
|
583
|
+
const result = await response.json();
|
|
584
|
+
return result.data;
|
|
585
|
+
}
|
|
586
|
+
async updateConfigRequest(config) {
|
|
587
|
+
const response = await this.fetch("/config", {
|
|
588
|
+
method: "PUT",
|
|
589
|
+
body: JSON.stringify(config)
|
|
590
|
+
});
|
|
591
|
+
const result = await response.json();
|
|
592
|
+
return result.data;
|
|
593
|
+
}
|
|
594
|
+
// ============================================================
|
|
595
|
+
// MCP API
|
|
596
|
+
// ============================================================
|
|
597
|
+
async listMCPServersRequest() {
|
|
598
|
+
const response = await this.fetch("/mcp/servers");
|
|
599
|
+
const result = await response.json();
|
|
600
|
+
return result.data;
|
|
601
|
+
}
|
|
602
|
+
async connectMCPServerRequest(serverName) {
|
|
603
|
+
const response = await this.fetch(`/mcp/servers/${serverName}/connect`, {
|
|
604
|
+
method: "POST"
|
|
605
|
+
});
|
|
606
|
+
const result = await response.json();
|
|
607
|
+
return result.data;
|
|
608
|
+
}
|
|
609
|
+
async disconnectMCPServerRequest(serverName) {
|
|
610
|
+
await this.fetch(`/mcp/servers/${serverName}/disconnect`, {
|
|
611
|
+
method: "POST"
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
// ============================================================
|
|
615
|
+
// Internal
|
|
616
|
+
// ============================================================
|
|
617
|
+
async fetch(path, options = {}) {
|
|
618
|
+
const url = `${this.baseUrl}${path}`;
|
|
619
|
+
const controller = new AbortController();
|
|
620
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
621
|
+
try {
|
|
622
|
+
const response = await fetch(url, {
|
|
623
|
+
...options,
|
|
624
|
+
headers: {
|
|
625
|
+
...this.headers,
|
|
626
|
+
...options.headers || {}
|
|
627
|
+
},
|
|
628
|
+
signal: controller.signal
|
|
629
|
+
});
|
|
630
|
+
if (!response.ok) {
|
|
631
|
+
const error = await response.json().catch(() => ({}));
|
|
632
|
+
throw new PybAPIError(
|
|
633
|
+
error.error?.code ?? "UNKNOWN_ERROR",
|
|
634
|
+
error.error?.message ?? `HTTP ${response.status}`,
|
|
635
|
+
error.error?.details
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
return response;
|
|
639
|
+
} finally {
|
|
640
|
+
clearTimeout(timeoutId);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
var PybAPIError = class extends Error {
|
|
645
|
+
constructor(code, message, details) {
|
|
646
|
+
super(message);
|
|
647
|
+
this.code = code;
|
|
648
|
+
this.details = details;
|
|
649
|
+
this.name = "PybAPIError";
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// src/sse.ts
|
|
654
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
655
|
+
var DEFAULT_FIRST_EVENT_TIMEOUT_MS = 15e3;
|
|
656
|
+
var DEFAULT_CHUNK_TIMEOUT_MS = 3e4;
|
|
657
|
+
var DEFAULT_RECONNECT_BASE_MS = 3e3;
|
|
658
|
+
var DEFAULT_RECONNECT_MAX_MS = 3e4;
|
|
659
|
+
var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
|
|
660
|
+
var DEFAULT_DEDUP_WINDOW_SIZE = 200;
|
|
661
|
+
var EventDeduplicator = class {
|
|
662
|
+
seen = /* @__PURE__ */ new Map();
|
|
663
|
+
duplicateCount = 0;
|
|
664
|
+
windowSize;
|
|
665
|
+
constructor(windowSize = DEFAULT_DEDUP_WINDOW_SIZE) {
|
|
666
|
+
this.windowSize = windowSize;
|
|
667
|
+
}
|
|
668
|
+
isDuplicate(eventId) {
|
|
669
|
+
return this.seen.has(eventId);
|
|
670
|
+
}
|
|
671
|
+
markSeen(eventId) {
|
|
672
|
+
if (this.seen.has(eventId)) {
|
|
673
|
+
this.duplicateCount++;
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
this.seen.set(eventId, Date.now());
|
|
677
|
+
if (this.seen.size > this.windowSize) {
|
|
678
|
+
const oldest = this.seen.keys().next().value;
|
|
679
|
+
if (oldest) {
|
|
680
|
+
this.seen.delete(oldest);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
getStats() {
|
|
685
|
+
return {
|
|
686
|
+
totalSeen: this.seen.size,
|
|
687
|
+
duplicateCount: this.duplicateCount,
|
|
688
|
+
windowSize: this.windowSize
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
function readPositiveInteger(value) {
|
|
693
|
+
const parsed = Number(value);
|
|
694
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
695
|
+
return Math.floor(parsed);
|
|
696
|
+
}
|
|
697
|
+
return void 0;
|
|
698
|
+
}
|
|
699
|
+
function resolveSSEClientRuntimeConfig(input) {
|
|
700
|
+
const env = input.env ?? process.env;
|
|
701
|
+
const options = input.options ?? {};
|
|
702
|
+
const reconnectBaseMs = readPositiveInteger(options.reconnectBaseMs ?? options.reconnectInterval) ?? readPositiveInteger(env.PYB_SSE_RECONNECT_BASE_MS) ?? DEFAULT_RECONNECT_BASE_MS;
|
|
703
|
+
const reconnectMaxMs = readPositiveInteger(options.reconnectMaxMs) ?? readPositiveInteger(env.PYB_SSE_RECONNECT_MAX_MS) ?? DEFAULT_RECONNECT_MAX_MS;
|
|
704
|
+
const maxReconnectAttempts = readPositiveInteger(options.maxReconnectAttempts) ?? readPositiveInteger(env.PYB_SSE_MAX_RECONNECT_ATTEMPTS) ?? DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
705
|
+
return {
|
|
706
|
+
connectTimeoutMs: readPositiveInteger(options.connectTimeoutMs) ?? readPositiveInteger(env.PYB_SSE_CONNECT_TIMEOUT_MS) ?? DEFAULT_CONNECT_TIMEOUT_MS,
|
|
707
|
+
firstEventTimeoutMs: readPositiveInteger(options.firstEventTimeoutMs) ?? readPositiveInteger(env.PYB_SSE_FIRST_EVENT_TIMEOUT_MS) ?? DEFAULT_FIRST_EVENT_TIMEOUT_MS,
|
|
708
|
+
chunkTimeoutMs: readPositiveInteger(options.chunkTimeoutMs) ?? readPositiveInteger(env.PYB_SSE_CHUNK_TIMEOUT_MS) ?? DEFAULT_CHUNK_TIMEOUT_MS,
|
|
709
|
+
reconnectBaseMs,
|
|
710
|
+
reconnectMaxMs: Math.max(reconnectMaxMs, reconnectBaseMs),
|
|
711
|
+
maxReconnectAttempts
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
var SSEClient = class {
|
|
715
|
+
baseUrl;
|
|
716
|
+
reconnectBaseMs;
|
|
717
|
+
reconnectMaxMs;
|
|
718
|
+
maxReconnectAttempts;
|
|
719
|
+
connectTimeoutMs;
|
|
720
|
+
firstEventTimeoutMs;
|
|
721
|
+
chunkTimeoutMs;
|
|
722
|
+
sessionIds;
|
|
723
|
+
eventTypes;
|
|
724
|
+
lastReceivedEventId;
|
|
725
|
+
deduplicator;
|
|
726
|
+
replayCount = 0;
|
|
727
|
+
replayGapCount = 0;
|
|
728
|
+
duplicateCount = 0;
|
|
729
|
+
eventSource = null;
|
|
730
|
+
callbacks = /* @__PURE__ */ new Map();
|
|
731
|
+
wildcardCallbacks = /* @__PURE__ */ new Set();
|
|
732
|
+
reconnectAttempts = 0;
|
|
733
|
+
reconnectDelayMs = 0;
|
|
734
|
+
lastDisconnectReason = null;
|
|
735
|
+
lastEventAt = null;
|
|
736
|
+
isConnecting = false;
|
|
737
|
+
shouldReconnect = true;
|
|
738
|
+
hasReceivedFirstEvent = false;
|
|
739
|
+
connectTimeoutTimer = null;
|
|
740
|
+
firstEventTimeoutTimer = null;
|
|
741
|
+
chunkTimeoutTimer = null;
|
|
742
|
+
constructor(options = {}) {
|
|
743
|
+
const runtimeConfig = resolveSSEClientRuntimeConfig({
|
|
744
|
+
options,
|
|
745
|
+
env: process.env
|
|
746
|
+
});
|
|
747
|
+
this.baseUrl = options.baseUrl ?? "http://localhost:4096/v1";
|
|
748
|
+
this.reconnectBaseMs = runtimeConfig.reconnectBaseMs;
|
|
749
|
+
this.reconnectMaxMs = runtimeConfig.reconnectMaxMs;
|
|
750
|
+
this.maxReconnectAttempts = runtimeConfig.maxReconnectAttempts;
|
|
751
|
+
this.connectTimeoutMs = runtimeConfig.connectTimeoutMs;
|
|
752
|
+
this.firstEventTimeoutMs = runtimeConfig.firstEventTimeoutMs;
|
|
753
|
+
this.chunkTimeoutMs = runtimeConfig.chunkTimeoutMs;
|
|
754
|
+
this.sessionIds = options.sessionIds;
|
|
755
|
+
this.eventTypes = options.eventTypes;
|
|
756
|
+
this.lastReceivedEventId = options.lastEventId ?? null;
|
|
757
|
+
this.deduplicator = new EventDeduplicator(options.dedupWindowSize ?? DEFAULT_DEDUP_WINDOW_SIZE);
|
|
758
|
+
}
|
|
759
|
+
connect() {
|
|
760
|
+
if (this.eventSource || this.isConnecting) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
this.isConnecting = true;
|
|
764
|
+
this.shouldReconnect = true;
|
|
765
|
+
this.hasReceivedFirstEvent = false;
|
|
766
|
+
const params = new URLSearchParams();
|
|
767
|
+
if (this.sessionIds?.length) {
|
|
768
|
+
params.set("sessionIds", this.sessionIds.join(","));
|
|
769
|
+
}
|
|
770
|
+
if (this.eventTypes?.length) {
|
|
771
|
+
params.set("eventTypes", this.eventTypes.join(","));
|
|
772
|
+
}
|
|
773
|
+
const url = this.buildEventsUrl(params);
|
|
774
|
+
try {
|
|
775
|
+
this.eventSource = new EventSource(url);
|
|
776
|
+
this.setupConnectTimeout();
|
|
777
|
+
this.eventSource.onopen = () => {
|
|
778
|
+
this.isConnecting = false;
|
|
779
|
+
this.reconnectAttempts = 0;
|
|
780
|
+
this.clearConnectTimeout();
|
|
781
|
+
this.setupFirstEventTimeout();
|
|
782
|
+
this.emitDiagnosticEvent("connected");
|
|
783
|
+
};
|
|
784
|
+
this.eventSource.onerror = () => {
|
|
785
|
+
this.handleDisconnect("event_source_error");
|
|
786
|
+
};
|
|
787
|
+
this.eventSource.onmessage = (event) => {
|
|
788
|
+
this.handleMessage(event);
|
|
789
|
+
};
|
|
790
|
+
const eventTypes = [
|
|
791
|
+
"server.connected",
|
|
792
|
+
"server.heartbeat",
|
|
793
|
+
"server.status",
|
|
794
|
+
"session.created",
|
|
795
|
+
"session.updated",
|
|
796
|
+
"session.deleted",
|
|
797
|
+
"message.created",
|
|
798
|
+
"message.updated",
|
|
799
|
+
"message.completed",
|
|
800
|
+
"request.started",
|
|
801
|
+
"request.completed",
|
|
802
|
+
"tool.started",
|
|
803
|
+
"tool.progress",
|
|
804
|
+
"tool.completed",
|
|
805
|
+
"tool.error",
|
|
806
|
+
"permission.requested",
|
|
807
|
+
"permission.responded",
|
|
808
|
+
"permission.timeout",
|
|
809
|
+
"mcp.status",
|
|
810
|
+
"error",
|
|
811
|
+
"error.stream",
|
|
812
|
+
"sse.replay",
|
|
813
|
+
"sse.replay_gap",
|
|
814
|
+
"sse.dedup"
|
|
815
|
+
];
|
|
816
|
+
for (const eventType of eventTypes) {
|
|
817
|
+
this.eventSource.addEventListener(eventType, (event) => {
|
|
818
|
+
this.handleMessage(event);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
} catch (error) {
|
|
822
|
+
this.isConnecting = false;
|
|
823
|
+
this.attemptReconnect();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
disconnect() {
|
|
827
|
+
this.shouldReconnect = false;
|
|
828
|
+
this.clearAllTimeouts();
|
|
829
|
+
if (this.eventSource) {
|
|
830
|
+
this.eventSource.close();
|
|
831
|
+
this.eventSource = null;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
subscribe(eventType, callback) {
|
|
835
|
+
if (!this.callbacks.has(eventType)) {
|
|
836
|
+
this.callbacks.set(eventType, /* @__PURE__ */ new Set());
|
|
837
|
+
}
|
|
838
|
+
this.callbacks.get(eventType).add(callback);
|
|
839
|
+
return () => {
|
|
840
|
+
this.callbacks.get(eventType)?.delete(callback);
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
subscribeAll(callback) {
|
|
844
|
+
this.wildcardCallbacks.add(callback);
|
|
845
|
+
return () => {
|
|
846
|
+
this.wildcardCallbacks.delete(callback);
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
subscribeFiltered(filter, callback) {
|
|
850
|
+
const wrapped = (event) => {
|
|
851
|
+
if (filter.sessionId) {
|
|
852
|
+
const sessionId = "sessionId" in event && typeof event.sessionId === "string" ? event.sessionId : void 0;
|
|
853
|
+
if (sessionId !== filter.sessionId) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (filter.type) {
|
|
858
|
+
if (Array.isArray(filter.type)) {
|
|
859
|
+
if (!filter.type.includes(event.type)) {
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
} else if (event.type !== filter.type) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
if (filter.predicate && !filter.predicate(event)) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
callback(event);
|
|
870
|
+
};
|
|
871
|
+
return this.subscribeAll(wrapped);
|
|
872
|
+
}
|
|
873
|
+
handleMessage(event) {
|
|
874
|
+
try {
|
|
875
|
+
const rawData = JSON.parse(event.data);
|
|
876
|
+
const rawEventId = typeof rawData?.id === "string" ? rawData.id : null;
|
|
877
|
+
if (rawEventId) {
|
|
878
|
+
if (this.deduplicator.isDuplicate(rawEventId)) {
|
|
879
|
+
this.duplicateCount++;
|
|
880
|
+
this.emitDedupDiagnosticEvent();
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
this.deduplicator.markSeen(rawEventId);
|
|
884
|
+
this.lastReceivedEventId = rawEventId;
|
|
885
|
+
}
|
|
886
|
+
const parseResult = PybSSEEventSchema.safeParse(rawData);
|
|
887
|
+
if (parseResult.success) {
|
|
888
|
+
this.lastEventAt = Date.now();
|
|
889
|
+
if (!this.hasReceivedFirstEvent) {
|
|
890
|
+
this.hasReceivedFirstEvent = true;
|
|
891
|
+
this.clearFirstEventTimeout();
|
|
892
|
+
}
|
|
893
|
+
this.resetChunkTimeout();
|
|
894
|
+
const typedEvent = parseResult.data;
|
|
895
|
+
if (typedEvent.type === "sse.replay") {
|
|
896
|
+
const replayCount = typedEvent.data?.replayCount;
|
|
897
|
+
const replayGapCount = typedEvent.data?.replayGapCount;
|
|
898
|
+
if (typeof replayCount === "number") this.replayCount = replayCount;
|
|
899
|
+
if (typeof replayGapCount === "number") this.replayGapCount = replayGapCount;
|
|
900
|
+
}
|
|
901
|
+
if (typedEvent.type === "sse.replay_gap") {
|
|
902
|
+
this.replayGapCount++;
|
|
903
|
+
}
|
|
904
|
+
this.emit(typedEvent.type, typedEvent);
|
|
905
|
+
}
|
|
906
|
+
} catch (error) {
|
|
907
|
+
console.error("Failed to parse SSE event:", error);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
emit(eventType, event) {
|
|
911
|
+
const callbacks = this.callbacks.get(eventType);
|
|
912
|
+
if (callbacks) {
|
|
913
|
+
for (const callback of callbacks) {
|
|
914
|
+
try {
|
|
915
|
+
callback(event);
|
|
916
|
+
} catch (error) {
|
|
917
|
+
console.error("Error in SSE callback:", error);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
for (const callback of this.wildcardCallbacks) {
|
|
922
|
+
try {
|
|
923
|
+
callback(event);
|
|
924
|
+
} catch (error) {
|
|
925
|
+
console.error("Error in SSE wildcard callback:", error);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
handleDisconnect(reason) {
|
|
930
|
+
this.eventSource?.close();
|
|
931
|
+
this.eventSource = null;
|
|
932
|
+
this.isConnecting = false;
|
|
933
|
+
this.lastDisconnectReason = reason;
|
|
934
|
+
this.clearAllTimeouts();
|
|
935
|
+
this.emitDiagnosticEvent("disconnected");
|
|
936
|
+
if (this.shouldReconnect) {
|
|
937
|
+
this.attemptReconnect();
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
attemptReconnect() {
|
|
941
|
+
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
|
|
942
|
+
console.error("Max reconnect attempts reached");
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
this.reconnectAttempts++;
|
|
946
|
+
const delay = Math.min(
|
|
947
|
+
this.reconnectBaseMs * Math.pow(2, this.reconnectAttempts - 1),
|
|
948
|
+
this.reconnectMaxMs
|
|
949
|
+
);
|
|
950
|
+
this.reconnectDelayMs = delay;
|
|
951
|
+
this.emitDiagnosticEvent("reconnect_scheduled");
|
|
952
|
+
setTimeout(() => {
|
|
953
|
+
if (this.shouldReconnect) {
|
|
954
|
+
this.connect();
|
|
955
|
+
}
|
|
956
|
+
}, delay);
|
|
957
|
+
}
|
|
958
|
+
setupConnectTimeout() {
|
|
959
|
+
this.clearConnectTimeout();
|
|
960
|
+
this.connectTimeoutTimer = setTimeout(() => {
|
|
961
|
+
this.handleDisconnect("connect_timeout");
|
|
962
|
+
}, this.connectTimeoutMs);
|
|
963
|
+
}
|
|
964
|
+
setupFirstEventTimeout() {
|
|
965
|
+
this.clearFirstEventTimeout();
|
|
966
|
+
this.firstEventTimeoutTimer = setTimeout(() => {
|
|
967
|
+
this.handleDisconnect("first_event_timeout");
|
|
968
|
+
}, this.firstEventTimeoutMs);
|
|
969
|
+
}
|
|
970
|
+
resetChunkTimeout() {
|
|
971
|
+
this.clearChunkTimeout();
|
|
972
|
+
this.chunkTimeoutTimer = setTimeout(() => {
|
|
973
|
+
this.handleDisconnect("chunk_timeout");
|
|
974
|
+
}, this.chunkTimeoutMs);
|
|
975
|
+
}
|
|
976
|
+
clearConnectTimeout() {
|
|
977
|
+
if (this.connectTimeoutTimer) {
|
|
978
|
+
clearTimeout(this.connectTimeoutTimer);
|
|
979
|
+
this.connectTimeoutTimer = null;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
clearFirstEventTimeout() {
|
|
983
|
+
if (this.firstEventTimeoutTimer) {
|
|
984
|
+
clearTimeout(this.firstEventTimeoutTimer);
|
|
985
|
+
this.firstEventTimeoutTimer = null;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
clearChunkTimeout() {
|
|
989
|
+
if (this.chunkTimeoutTimer) {
|
|
990
|
+
clearTimeout(this.chunkTimeoutTimer);
|
|
991
|
+
this.chunkTimeoutTimer = null;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
clearAllTimeouts() {
|
|
995
|
+
this.clearConnectTimeout();
|
|
996
|
+
this.clearFirstEventTimeout();
|
|
997
|
+
this.clearChunkTimeout();
|
|
998
|
+
}
|
|
999
|
+
emitDiagnosticEvent(phase) {
|
|
1000
|
+
this.emit("sse.diagnostic", {
|
|
1001
|
+
type: "sse.diagnostic",
|
|
1002
|
+
timestamp: Date.now(),
|
|
1003
|
+
data: {
|
|
1004
|
+
phase,
|
|
1005
|
+
reconnectAttempts: this.reconnectAttempts,
|
|
1006
|
+
reconnectDelayMs: this.reconnectDelayMs,
|
|
1007
|
+
lastDisconnectReason: this.lastDisconnectReason,
|
|
1008
|
+
lastEventAt: this.lastEventAt
|
|
1009
|
+
}
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
emitDedupDiagnosticEvent() {
|
|
1013
|
+
const stats = this.deduplicator.getStats();
|
|
1014
|
+
this.emit("sse.dedup", {
|
|
1015
|
+
type: "sse.dedup",
|
|
1016
|
+
timestamp: Date.now(),
|
|
1017
|
+
data: {
|
|
1018
|
+
duplicateCount: this.duplicateCount,
|
|
1019
|
+
totalSeen: stats.totalSeen,
|
|
1020
|
+
windowSize: stats.windowSize
|
|
1021
|
+
}
|
|
1022
|
+
});
|
|
1023
|
+
}
|
|
1024
|
+
buildEventsUrl(params) {
|
|
1025
|
+
if (this.lastReceivedEventId) {
|
|
1026
|
+
params.set("lastEventId", this.lastReceivedEventId);
|
|
1027
|
+
}
|
|
1028
|
+
return `${this.baseUrl}/events${params.toString() ? `?${params}` : ""}`;
|
|
1029
|
+
}
|
|
1030
|
+
isConnected() {
|
|
1031
|
+
return this.eventSource?.readyState === EventSource.OPEN;
|
|
1032
|
+
}
|
|
1033
|
+
getReconnectAttempts() {
|
|
1034
|
+
return this.reconnectAttempts;
|
|
1035
|
+
}
|
|
1036
|
+
getDiagnostics() {
|
|
1037
|
+
return {
|
|
1038
|
+
reconnectAttempts: this.reconnectAttempts,
|
|
1039
|
+
reconnectDelayMs: this.reconnectDelayMs,
|
|
1040
|
+
lastDisconnectReason: this.lastDisconnectReason,
|
|
1041
|
+
lastEventAt: this.lastEventAt
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
getResumptionDiagnostics() {
|
|
1045
|
+
return {
|
|
1046
|
+
lastReceivedEventId: this.lastReceivedEventId,
|
|
1047
|
+
replayCount: this.replayCount,
|
|
1048
|
+
replayGapCount: this.replayGapCount,
|
|
1049
|
+
duplicateCount: this.duplicateCount
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
function createSSEClient(options) {
|
|
1054
|
+
return new SSEClient(options);
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
// src/v2/message.ts
|
|
1058
|
+
var import_zod2 = require("zod");
|
|
1059
|
+
var V2MessageContentTextSchema = import_zod2.z.object({
|
|
1060
|
+
type: import_zod2.z.literal("text"),
|
|
1061
|
+
text: import_zod2.z.string()
|
|
1062
|
+
});
|
|
1063
|
+
var V2MessageSchema = import_zod2.z.object({
|
|
1064
|
+
id: import_zod2.z.string(),
|
|
1065
|
+
role: import_zod2.z.enum(["user", "assistant", "system"]),
|
|
1066
|
+
channel: import_zod2.z.enum(["runtime", "protocol"]),
|
|
1067
|
+
content: import_zod2.z.array(V2MessageContentTextSchema).min(1),
|
|
1068
|
+
finishReason: import_zod2.z.enum(["end_turn", "tool_calls", "max_tokens", "unknown"]),
|
|
1069
|
+
timestamp: import_zod2.z.number().int()
|
|
1070
|
+
});
|
|
1071
|
+
function normalizeTextContent(content) {
|
|
1072
|
+
if (Array.isArray(content)) {
|
|
1073
|
+
const textParts = content.filter((item) => typeof item === "object" && item !== null).map((item) => item.type === "text" && typeof item.text === "string" ? item.text : "").filter(Boolean);
|
|
1074
|
+
if (textParts.length > 0) return textParts.join("\n");
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof content === "string") return content;
|
|
1077
|
+
return "";
|
|
1078
|
+
}
|
|
1079
|
+
function coerceFinishReason(value) {
|
|
1080
|
+
if (value === "end_turn" || value === "tool_calls" || value === "max_tokens") return value;
|
|
1081
|
+
return "unknown";
|
|
1082
|
+
}
|
|
1083
|
+
function mapRuntimeMessageToV2(message) {
|
|
1084
|
+
const text = normalizeTextContent(message?.message?.content);
|
|
1085
|
+
return {
|
|
1086
|
+
id: String(message?.uuid ?? message?.message?.id ?? `runtime-${Date.now()}`),
|
|
1087
|
+
role: message?.type === "assistant" ? "assistant" : message?.type === "user" ? "user" : "system",
|
|
1088
|
+
channel: "runtime",
|
|
1089
|
+
content: [{ type: "text", text: text || `[${String(message?.type ?? "runtime")}]` }],
|
|
1090
|
+
finishReason: coerceFinishReason(message?.finish ?? message?.message?.stop_reason),
|
|
1091
|
+
timestamp: Date.now()
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
function mapV1MessageToV2(message) {
|
|
1095
|
+
const text = normalizeTextContent(message?.content);
|
|
1096
|
+
const role = message?.role === "assistant" || message?.role === "user" ? message.role : "system";
|
|
1097
|
+
return {
|
|
1098
|
+
id: String(message?.id ?? `protocol-${Date.now()}`),
|
|
1099
|
+
role,
|
|
1100
|
+
channel: "protocol",
|
|
1101
|
+
content: [{ type: "text", text: text || "[protocol-message]" }],
|
|
1102
|
+
finishReason: "unknown",
|
|
1103
|
+
timestamp: Number.isFinite(message?.timestamp) ? Number(message.timestamp) : Date.now()
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
function validateV2Message(message) {
|
|
1107
|
+
return V2MessageSchema.safeParse(message);
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// src/v2/toolUseContext.ts
|
|
1111
|
+
var import_zod3 = require("zod");
|
|
1112
|
+
var PermissionModeSchema = import_zod3.z.enum([
|
|
1113
|
+
"default",
|
|
1114
|
+
"acceptEdits",
|
|
1115
|
+
"plan",
|
|
1116
|
+
"bypassPermissions",
|
|
1117
|
+
"dontAsk"
|
|
1118
|
+
]);
|
|
1119
|
+
var V2ToolUseContextSchema = import_zod3.z.object({
|
|
1120
|
+
requestId: import_zod3.z.string(),
|
|
1121
|
+
messageId: import_zod3.z.string().optional(),
|
|
1122
|
+
abortController: import_zod3.z.any(),
|
|
1123
|
+
readFileTimestamps: import_zod3.z.record(import_zod3.z.string(), import_zod3.z.number()),
|
|
1124
|
+
options: import_zod3.z.object({
|
|
1125
|
+
permissionMode: PermissionModeSchema,
|
|
1126
|
+
typedSessionWriteEnabled: import_zod3.z.boolean(),
|
|
1127
|
+
compactionBoundaryEnabled: import_zod3.z.boolean(),
|
|
1128
|
+
toolOutputLifecycleEnabled: import_zod3.z.boolean(),
|
|
1129
|
+
singleFactLayerReadEnabled: import_zod3.z.boolean(),
|
|
1130
|
+
tools: import_zod3.z.array(import_zod3.z.any()).optional(),
|
|
1131
|
+
commands: import_zod3.z.array(import_zod3.z.any()).optional(),
|
|
1132
|
+
verbose: import_zod3.z.boolean().optional(),
|
|
1133
|
+
safeMode: import_zod3.z.boolean().optional()
|
|
1134
|
+
})
|
|
1135
|
+
});
|
|
1136
|
+
function resolvePermissionMode(skipPermissions) {
|
|
1137
|
+
return skipPermissions ? "bypassPermissions" : "default";
|
|
1138
|
+
}
|
|
1139
|
+
function buildV2ToolUseContextFromPromptRequest(input) {
|
|
1140
|
+
return {
|
|
1141
|
+
requestId: input.requestId,
|
|
1142
|
+
messageId: input.messageId,
|
|
1143
|
+
abortController: new AbortController(),
|
|
1144
|
+
readFileTimestamps: {},
|
|
1145
|
+
options: {
|
|
1146
|
+
permissionMode: resolvePermissionMode(input.promptRequest?.options?.skipPermissions),
|
|
1147
|
+
typedSessionWriteEnabled: true,
|
|
1148
|
+
compactionBoundaryEnabled: false,
|
|
1149
|
+
toolOutputLifecycleEnabled: false,
|
|
1150
|
+
singleFactLayerReadEnabled: true
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
function isToolAutoExecutableInContext(input) {
|
|
1155
|
+
if (input.requiresUserInteraction) return false;
|
|
1156
|
+
if (input.context.options.permissionMode === "dontAsk") return false;
|
|
1157
|
+
return true;
|
|
1158
|
+
}
|
|
1159
|
+
function validateV2ToolUseContext(context) {
|
|
1160
|
+
return V2ToolUseContextSchema.safeParse(context);
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/v2/session.ts
|
|
1164
|
+
var import_zod4 = require("zod");
|
|
1165
|
+
var V2SessionStatusSchema = import_zod4.z.enum([
|
|
1166
|
+
"idle",
|
|
1167
|
+
"running",
|
|
1168
|
+
"blocked",
|
|
1169
|
+
"errored",
|
|
1170
|
+
"closed"
|
|
1171
|
+
]);
|
|
1172
|
+
var V2RequestStatusSchema = import_zod4.z.enum([
|
|
1173
|
+
"idle",
|
|
1174
|
+
"running",
|
|
1175
|
+
"interrupted",
|
|
1176
|
+
"errored",
|
|
1177
|
+
"closed"
|
|
1178
|
+
]);
|
|
1179
|
+
var V2SessionSchema = import_zod4.z.object({
|
|
1180
|
+
id: import_zod4.z.string(),
|
|
1181
|
+
status: V2SessionStatusSchema,
|
|
1182
|
+
requestStatus: V2RequestStatusSchema,
|
|
1183
|
+
messageCount: import_zod4.z.number().int().nonnegative(),
|
|
1184
|
+
createdAt: import_zod4.z.number().int(),
|
|
1185
|
+
updatedAt: import_zod4.z.number().int(),
|
|
1186
|
+
config: import_zod4.z.object({
|
|
1187
|
+
model: import_zod4.z.string(),
|
|
1188
|
+
agent: import_zod4.z.string(),
|
|
1189
|
+
outputStyle: import_zod4.z.string()
|
|
1190
|
+
})
|
|
1191
|
+
});
|
|
1192
|
+
var transitionTable = {
|
|
1193
|
+
idle: ["idle", "running", "closed", "errored"],
|
|
1194
|
+
running: ["running", "idle", "blocked", "errored", "closed"],
|
|
1195
|
+
blocked: ["blocked", "running", "idle", "errored", "closed"],
|
|
1196
|
+
errored: ["errored", "idle", "closed"],
|
|
1197
|
+
closed: ["closed"]
|
|
1198
|
+
};
|
|
1199
|
+
function canTransitionV2SessionStatus(from, to) {
|
|
1200
|
+
return transitionTable[from].includes(to);
|
|
1201
|
+
}
|
|
1202
|
+
function mapRuntimeSessionStatusToV2(status) {
|
|
1203
|
+
if (status === "processing") return "running";
|
|
1204
|
+
if (status === "waiting_permission") return "blocked";
|
|
1205
|
+
if (status === "error") return "errored";
|
|
1206
|
+
return "idle";
|
|
1207
|
+
}
|
|
1208
|
+
function mapV1SessionStatusToV2(status) {
|
|
1209
|
+
if (status === "active") return "running";
|
|
1210
|
+
if (status === "archived") return "closed";
|
|
1211
|
+
return "idle";
|
|
1212
|
+
}
|
|
1213
|
+
function validateV2Session(session) {
|
|
1214
|
+
return V2SessionSchema.safeParse(session);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// src/v2/dualTrackEvaluation.ts
|
|
1218
|
+
var import_zod5 = require("zod");
|
|
1219
|
+
var DualTrackRawStatsSchema = import_zod5.z.object({
|
|
1220
|
+
totalRequests: import_zod5.z.number().int().nonnegative(),
|
|
1221
|
+
v1SuccessCount: import_zod5.z.number().int().nonnegative(),
|
|
1222
|
+
v2SuccessCount: import_zod5.z.number().int().nonnegative(),
|
|
1223
|
+
diffCount: import_zod5.z.number().int().nonnegative(),
|
|
1224
|
+
unmappableCount: import_zod5.z.number().int().nonnegative(),
|
|
1225
|
+
rollbackTriggerCount: import_zod5.z.number().int().nonnegative()
|
|
1226
|
+
});
|
|
1227
|
+
var DualTrackMetricsSchema = import_zod5.z.object({
|
|
1228
|
+
totalRequests: import_zod5.z.number().int().nonnegative(),
|
|
1229
|
+
successRate: import_zod5.z.number().min(0).max(1),
|
|
1230
|
+
diffRate: import_zod5.z.number().min(0).max(1),
|
|
1231
|
+
unmappableRate: import_zod5.z.number().min(0).max(1),
|
|
1232
|
+
rollbackTriggerCount: import_zod5.z.number().int().nonnegative()
|
|
1233
|
+
});
|
|
1234
|
+
var DualTrackThresholdsSchema = import_zod5.z.object({
|
|
1235
|
+
minSuccessRate: import_zod5.z.number().min(0).max(1),
|
|
1236
|
+
maxDiffRate: import_zod5.z.number().min(0).max(1),
|
|
1237
|
+
maxUnmappableRate: import_zod5.z.number().min(0).max(1),
|
|
1238
|
+
maxRollbackTriggers: import_zod5.z.number().int().nonnegative()
|
|
1239
|
+
});
|
|
1240
|
+
function buildDefaultDualTrackThresholds() {
|
|
1241
|
+
return {
|
|
1242
|
+
minSuccessRate: 0.99,
|
|
1243
|
+
maxDiffRate: 0.01,
|
|
1244
|
+
maxUnmappableRate: 0.01,
|
|
1245
|
+
maxRollbackTriggers: 0
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
function ratio(count, total) {
|
|
1249
|
+
if (total <= 0) return 0;
|
|
1250
|
+
return Number((count / total).toFixed(6));
|
|
1251
|
+
}
|
|
1252
|
+
function evaluateDualTrackMetrics(input) {
|
|
1253
|
+
const stats = DualTrackRawStatsSchema.parse(input);
|
|
1254
|
+
const effectiveSuccessCount = Math.min(stats.v1SuccessCount, stats.v2SuccessCount);
|
|
1255
|
+
return {
|
|
1256
|
+
totalRequests: stats.totalRequests,
|
|
1257
|
+
successRate: ratio(effectiveSuccessCount, stats.totalRequests),
|
|
1258
|
+
diffRate: ratio(stats.diffCount, stats.totalRequests),
|
|
1259
|
+
unmappableRate: ratio(stats.unmappableCount, stats.totalRequests),
|
|
1260
|
+
rollbackTriggerCount: stats.rollbackTriggerCount
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
function evaluateV1DeprecationReadiness(metricsInput, thresholdsInput) {
|
|
1264
|
+
const metrics = DualTrackMetricsSchema.parse(metricsInput);
|
|
1265
|
+
const thresholds = DualTrackThresholdsSchema.parse(thresholdsInput);
|
|
1266
|
+
const failedChecks = [];
|
|
1267
|
+
if (metrics.successRate < thresholds.minSuccessRate) failedChecks.push("minSuccessRate");
|
|
1268
|
+
if (metrics.diffRate > thresholds.maxDiffRate) failedChecks.push("maxDiffRate");
|
|
1269
|
+
if (metrics.unmappableRate > thresholds.maxUnmappableRate) failedChecks.push("maxUnmappableRate");
|
|
1270
|
+
if (metrics.rollbackTriggerCount > thresholds.maxRollbackTriggers) {
|
|
1271
|
+
failedChecks.push("maxRollbackTriggers");
|
|
1272
|
+
}
|
|
1273
|
+
return {
|
|
1274
|
+
ready: failedChecks.length === 0,
|
|
1275
|
+
failedChecks
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// src/v2/runtimeSession.types.ts
|
|
1280
|
+
var import_zod6 = require("zod");
|
|
1281
|
+
var RuntimeSessionStatusSchema = import_zod6.z.enum(["pending", "running", "closed"]);
|
|
1282
|
+
var RuntimeSessionInputSchema = import_zod6.z.object({
|
|
1283
|
+
message: import_zod6.z.string().min(1),
|
|
1284
|
+
attachments: import_zod6.z.array(import_zod6.z.record(import_zod6.z.unknown())).optional()
|
|
1285
|
+
});
|
|
1286
|
+
var RuntimeSessionEventSchema = import_zod6.z.discriminatedUnion("type", [
|
|
1287
|
+
import_zod6.z.object({
|
|
1288
|
+
type: import_zod6.z.literal("message.created"),
|
|
1289
|
+
data: import_zod6.z.record(import_zod6.z.unknown())
|
|
1290
|
+
}),
|
|
1291
|
+
import_zod6.z.object({
|
|
1292
|
+
type: import_zod6.z.literal("message.updated"),
|
|
1293
|
+
data: import_zod6.z.record(import_zod6.z.unknown()),
|
|
1294
|
+
delta: import_zod6.z.string().optional()
|
|
1295
|
+
}),
|
|
1296
|
+
import_zod6.z.object({
|
|
1297
|
+
type: import_zod6.z.literal("tool.started"),
|
|
1298
|
+
data: import_zod6.z.record(import_zod6.z.unknown())
|
|
1299
|
+
}),
|
|
1300
|
+
import_zod6.z.object({
|
|
1301
|
+
type: import_zod6.z.literal("tool.completed"),
|
|
1302
|
+
data: import_zod6.z.record(import_zod6.z.unknown())
|
|
1303
|
+
}),
|
|
1304
|
+
import_zod6.z.object({
|
|
1305
|
+
type: import_zod6.z.literal("request.completed"),
|
|
1306
|
+
data: import_zod6.z.record(import_zod6.z.unknown())
|
|
1307
|
+
}),
|
|
1308
|
+
import_zod6.z.object({
|
|
1309
|
+
type: import_zod6.z.literal("error"),
|
|
1310
|
+
data: import_zod6.z.record(import_zod6.z.unknown())
|
|
1311
|
+
}),
|
|
1312
|
+
import_zod6.z.object({
|
|
1313
|
+
type: import_zod6.z.literal("permission.decision"),
|
|
1314
|
+
data: import_zod6.z.object({
|
|
1315
|
+
decision: import_zod6.z.enum(["allow", "ask", "deny"]),
|
|
1316
|
+
reason: import_zod6.z.string(),
|
|
1317
|
+
source: import_zod6.z.enum(["callback", "policy", "default"]),
|
|
1318
|
+
tool: import_zod6.z.string(),
|
|
1319
|
+
requestId: import_zod6.z.string()
|
|
1320
|
+
})
|
|
1321
|
+
})
|
|
1322
|
+
]);
|
|
1323
|
+
|
|
1324
|
+
// src/v2/runtimePermission.ts
|
|
1325
|
+
var KNOWN_PERMISSION_MODES = [
|
|
1326
|
+
"default",
|
|
1327
|
+
"acceptEdits",
|
|
1328
|
+
"plan",
|
|
1329
|
+
"bypassPermissions",
|
|
1330
|
+
"dontAsk"
|
|
1331
|
+
];
|
|
1332
|
+
function resolvePermissionModeForSdk(input) {
|
|
1333
|
+
if (typeof input === "string" && KNOWN_PERMISSION_MODES.includes(input)) {
|
|
1334
|
+
return { permissionMode: input };
|
|
1335
|
+
}
|
|
1336
|
+
if (typeof input === "undefined") {
|
|
1337
|
+
return { permissionMode: "default" };
|
|
1338
|
+
}
|
|
1339
|
+
return {
|
|
1340
|
+
permissionMode: "default",
|
|
1341
|
+
invalidPermissionMode: input
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
function createRuntimePermissionContextForSession(input) {
|
|
1345
|
+
const modeResult = resolvePermissionModeForSdk(input.permissionPolicy?.permissionMode);
|
|
1346
|
+
const candidate = input.permissionPolicy?.toolPermissionContext ?? input.toolPermissionContext;
|
|
1347
|
+
const baseline = createDefaultToolPermissionContextForSdk({
|
|
1348
|
+
sessionId: input.sessionId,
|
|
1349
|
+
requestId: input.requestId,
|
|
1350
|
+
permissionMode: modeResult.permissionMode
|
|
1351
|
+
});
|
|
1352
|
+
const metadata = {
|
|
1353
|
+
...isPlainObject(candidate?.metadata) ? candidate.metadata : {}
|
|
1354
|
+
};
|
|
1355
|
+
if (typeof modeResult.invalidPermissionMode !== "undefined") {
|
|
1356
|
+
metadata.invalidPermissionMode = modeResult.invalidPermissionMode;
|
|
1357
|
+
}
|
|
1358
|
+
return {
|
|
1359
|
+
sessionId: typeof candidate?.sessionId === "string" ? candidate.sessionId : baseline.sessionId,
|
|
1360
|
+
requestId: typeof candidate?.requestId === "string" ? candidate.requestId : baseline.requestId,
|
|
1361
|
+
permissionMode: modeResult.permissionMode,
|
|
1362
|
+
cwd: typeof candidate?.cwd === "string" ? candidate.cwd : baseline.cwd,
|
|
1363
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : baseline.metadata
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
function isPlainObject(value) {
|
|
1367
|
+
return typeof value === "object" && value !== null;
|
|
1368
|
+
}
|
|
1369
|
+
function createDefaultToolPermissionContextForSdk(input) {
|
|
1370
|
+
return {
|
|
1371
|
+
sessionId: input.sessionId,
|
|
1372
|
+
requestId: input.requestId,
|
|
1373
|
+
permissionMode: input.permissionMode ?? "default",
|
|
1374
|
+
cwd: input.cwd,
|
|
1375
|
+
metadata: input.metadata
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
function resolvePermissionDecision(input) {
|
|
1379
|
+
const callbackDecision = ensureValidDecision(input.callbackDecision, "callback");
|
|
1380
|
+
if (callbackDecision) return callbackDecision;
|
|
1381
|
+
const policyDecision = ensureValidDecision(input.policyDecision, "policy");
|
|
1382
|
+
if (policyDecision) return policyDecision;
|
|
1383
|
+
const defaultDecision = ensureValidDecision(input.defaultDecision, "default");
|
|
1384
|
+
if (defaultDecision) return defaultDecision;
|
|
1385
|
+
return {
|
|
1386
|
+
decision: "deny",
|
|
1387
|
+
reason: "default-deny-fallback",
|
|
1388
|
+
source: "default"
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
function ensureValidDecision(decision, expectedSource) {
|
|
1392
|
+
if (!decision) return null;
|
|
1393
|
+
if (decision.source !== expectedSource) return null;
|
|
1394
|
+
if (decision.decision !== "allow" && decision.decision !== "ask" && decision.decision !== "deny") {
|
|
1395
|
+
return null;
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
decision: decision.decision,
|
|
1399
|
+
reason: typeof decision.reason === "string" ? decision.reason : "",
|
|
1400
|
+
source: decision.source
|
|
1401
|
+
};
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
// src/v2/runtimeEvent.types.ts
|
|
1405
|
+
var import_zod7 = require("zod");
|
|
1406
|
+
var RuntimeEventDomainSchema = import_zod7.z.enum([
|
|
1407
|
+
"message",
|
|
1408
|
+
"tool",
|
|
1409
|
+
"permission",
|
|
1410
|
+
"session",
|
|
1411
|
+
"lifecycle"
|
|
1412
|
+
]);
|
|
1413
|
+
var RuntimeEventSchema = import_zod7.z.object({
|
|
1414
|
+
domain: RuntimeEventDomainSchema,
|
|
1415
|
+
type: import_zod7.z.string().min(1),
|
|
1416
|
+
sessionId: import_zod7.z.string().min(1),
|
|
1417
|
+
timestamp: import_zod7.z.number().finite(),
|
|
1418
|
+
requestId: import_zod7.z.string().min(1).optional(),
|
|
1419
|
+
data: import_zod7.z.record(import_zod7.z.unknown())
|
|
1420
|
+
});
|
|
1421
|
+
|
|
1422
|
+
// src/v2/runtimeEventProjector.ts
|
|
1423
|
+
var RUNTIME_EVENT_MAPPING_RULES = {
|
|
1424
|
+
"message.created": { domain: "message", type: "message.created" },
|
|
1425
|
+
"message.updated": { domain: "message", type: "message.updated" },
|
|
1426
|
+
"tool.started": { domain: "tool", type: "tool.started" },
|
|
1427
|
+
"tool.progress": { domain: "tool", type: "tool.progress" },
|
|
1428
|
+
"tool.completed": { domain: "tool", type: "tool.completed" },
|
|
1429
|
+
"permission.decision": { domain: "permission", type: "permission.decision" },
|
|
1430
|
+
"session.state.changed": { domain: "session", type: "session.state.changed" },
|
|
1431
|
+
"session.completed": { domain: "session", type: "session.completed" },
|
|
1432
|
+
"session.error": { domain: "session", type: "session.error" },
|
|
1433
|
+
"request.completed": { domain: "session", type: "session.completed" },
|
|
1434
|
+
error: { domain: "session", type: "session.error" },
|
|
1435
|
+
"lifecycle.start-query": { domain: "lifecycle", type: "lifecycle.query.started" },
|
|
1436
|
+
"lifecycle.start-step": { domain: "lifecycle", type: "lifecycle.step.started" },
|
|
1437
|
+
"lifecycle.finish-step": { domain: "lifecycle", type: "lifecycle.step.finished" },
|
|
1438
|
+
"lifecycle.finish-query": { domain: "lifecycle", type: "lifecycle.query.finished" }
|
|
1439
|
+
};
|
|
1440
|
+
var LEGACY_EVENT_MAPPING_RULES = {
|
|
1441
|
+
"message.created": "message.created",
|
|
1442
|
+
"message.updated": "message.updated",
|
|
1443
|
+
"tool.started": "tool.started",
|
|
1444
|
+
"tool.progress": "tool.progress",
|
|
1445
|
+
"tool.completed": "tool.completed",
|
|
1446
|
+
"permission.decision": "permission.decision",
|
|
1447
|
+
"session.state.changed": "session.state.changed",
|
|
1448
|
+
"session.completed": "request.completed",
|
|
1449
|
+
"session.error": "error",
|
|
1450
|
+
"lifecycle.query.started": "lifecycle.start-query",
|
|
1451
|
+
"lifecycle.step.started": "lifecycle.start-step",
|
|
1452
|
+
"lifecycle.step.finished": "lifecycle.finish-step",
|
|
1453
|
+
"lifecycle.query.finished": "lifecycle.finish-query"
|
|
1454
|
+
};
|
|
1455
|
+
function getRuntimeEventMappingRules() {
|
|
1456
|
+
return { ...RUNTIME_EVENT_MAPPING_RULES };
|
|
1457
|
+
}
|
|
1458
|
+
function projectLegacyEventToRuntimeEvent(input) {
|
|
1459
|
+
const mappingRule = RUNTIME_EVENT_MAPPING_RULES[input.type];
|
|
1460
|
+
const domain = mappingRule?.domain ?? "session";
|
|
1461
|
+
const type = mappingRule?.type ?? "session.error";
|
|
1462
|
+
return RuntimeEventSchema.parse({
|
|
1463
|
+
domain,
|
|
1464
|
+
type,
|
|
1465
|
+
sessionId: input.sessionId,
|
|
1466
|
+
requestId: input.requestId,
|
|
1467
|
+
timestamp: input.timestamp ?? Date.now(),
|
|
1468
|
+
data: input.data
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
function projectRuntimeEventToLegacyEvent(input) {
|
|
1472
|
+
const legacyType = LEGACY_EVENT_MAPPING_RULES[input.type] ?? "error";
|
|
1473
|
+
const data = { ...input.data };
|
|
1474
|
+
if (legacyType === "request.completed" && typeof data.requestId === "undefined" && input.requestId) {
|
|
1475
|
+
data.requestId = input.requestId;
|
|
1476
|
+
}
|
|
1477
|
+
return {
|
|
1478
|
+
type: legacyType,
|
|
1479
|
+
data
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
// src/v2/runtimeSession.ts
|
|
1484
|
+
var DEFAULT_PERMISSION_CALLBACK_TIMEOUT_MS = 1e3;
|
|
1485
|
+
var DefaultQuerySessionExecutor = class {
|
|
1486
|
+
async *execute(_input) {
|
|
1487
|
+
}
|
|
1488
|
+
};
|
|
1489
|
+
var DefaultToolResolver = class {
|
|
1490
|
+
async resolve() {
|
|
1491
|
+
return [];
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1494
|
+
var DefaultPermissionEvaluator = class {
|
|
1495
|
+
async canUseTool() {
|
|
1496
|
+
return {
|
|
1497
|
+
decision: "allow",
|
|
1498
|
+
reason: "default-allow",
|
|
1499
|
+
source: "default"
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
var DefaultSessionEventPublisher = class {
|
|
1504
|
+
publish() {
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
function createRuntimeSession(config) {
|
|
1508
|
+
const querySessionExecutor = config.querySessionExecutor ?? new DefaultQuerySessionExecutor();
|
|
1509
|
+
const toolResolver = config.toolResolver ?? new DefaultToolResolver();
|
|
1510
|
+
const permissionEvaluator = config.permissionEvaluator ?? new DefaultPermissionEvaluator();
|
|
1511
|
+
const sessionEventPublisher = config.sessionEventPublisher ?? new DefaultSessionEventPublisher();
|
|
1512
|
+
let status = "pending";
|
|
1513
|
+
let pendingInput = null;
|
|
1514
|
+
const messages = (config.initialMessages ?? []).map(
|
|
1515
|
+
(input) => RuntimeSessionInputSchema.parse(input)
|
|
1516
|
+
);
|
|
1517
|
+
let turnId = 0;
|
|
1518
|
+
let abortController = new AbortController();
|
|
1519
|
+
let closed = false;
|
|
1520
|
+
let streamInProgress = false;
|
|
1521
|
+
function ensureOpen() {
|
|
1522
|
+
if (!closed) return;
|
|
1523
|
+
throw new Error("RUNTIME_SESSION_CLOSED");
|
|
1524
|
+
}
|
|
1525
|
+
async function* executeTurn(mode) {
|
|
1526
|
+
ensureOpen();
|
|
1527
|
+
if (streamInProgress) throw new Error("RUNTIME_SESSION_TURN_IN_PROGRESS");
|
|
1528
|
+
if (!pendingInput) throw new Error("RUNTIME_SESSION_INPUT_REQUIRED");
|
|
1529
|
+
streamInProgress = true;
|
|
1530
|
+
status = "running";
|
|
1531
|
+
const input = pendingInput;
|
|
1532
|
+
pendingInput = null;
|
|
1533
|
+
const tools = await toolResolver.resolve();
|
|
1534
|
+
const requestId = `${config.sessionId}-turn-${turnId}`;
|
|
1535
|
+
const runtimePermissionContext = createRuntimePermissionContextForSession({
|
|
1536
|
+
sessionId: config.sessionId,
|
|
1537
|
+
requestId,
|
|
1538
|
+
toolPermissionContext: config.toolPermissionContext,
|
|
1539
|
+
permissionPolicy: config.permissionPolicy
|
|
1540
|
+
});
|
|
1541
|
+
const stream = querySessionExecutor.execute(input, {
|
|
1542
|
+
abortSignal: abortController.signal,
|
|
1543
|
+
sessionId: config.sessionId,
|
|
1544
|
+
turnId,
|
|
1545
|
+
tools,
|
|
1546
|
+
messages: [...messages],
|
|
1547
|
+
runtimeContext: config.runtimeContext,
|
|
1548
|
+
toolPermissionContext: runtimePermissionContext,
|
|
1549
|
+
canUseTool: async (payload) => {
|
|
1550
|
+
const effectiveContext = payload.context ?? runtimePermissionContext;
|
|
1551
|
+
const callbackDecision = await resolveCallbackDecision({
|
|
1552
|
+
permissionPolicy: config.permissionPolicy,
|
|
1553
|
+
payload: {
|
|
1554
|
+
toolName: payload.toolName,
|
|
1555
|
+
toolInput: payload.toolInput,
|
|
1556
|
+
context: effectiveContext
|
|
1557
|
+
},
|
|
1558
|
+
timeoutMs: resolvePermissionCallbackTimeoutMs(config.permissionCallbackTimeoutMs)
|
|
1559
|
+
});
|
|
1560
|
+
const policyDecision = await resolvePolicyDecision({
|
|
1561
|
+
permissionEvaluator,
|
|
1562
|
+
payload: {
|
|
1563
|
+
toolName: payload.toolName,
|
|
1564
|
+
toolInput: payload.toolInput,
|
|
1565
|
+
context: effectiveContext
|
|
1566
|
+
}
|
|
1567
|
+
});
|
|
1568
|
+
const decision = resolvePermissionDecision({
|
|
1569
|
+
callbackDecision,
|
|
1570
|
+
policyDecision
|
|
1571
|
+
});
|
|
1572
|
+
await sessionEventPublisher.publish({
|
|
1573
|
+
type: "permission.decision",
|
|
1574
|
+
data: {
|
|
1575
|
+
decision: decision.decision,
|
|
1576
|
+
reason: decision.reason,
|
|
1577
|
+
source: decision.source,
|
|
1578
|
+
tool: payload.toolName,
|
|
1579
|
+
requestId
|
|
1580
|
+
}
|
|
1581
|
+
});
|
|
1582
|
+
return decision;
|
|
1583
|
+
}
|
|
1584
|
+
});
|
|
1585
|
+
try {
|
|
1586
|
+
for await (const event of stream) {
|
|
1587
|
+
if (mode === "legacy") {
|
|
1588
|
+
await sessionEventPublisher.publish(event);
|
|
1589
|
+
yield event;
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
const projected = projectEventToRuntimeEvent({
|
|
1593
|
+
event,
|
|
1594
|
+
sessionId: config.sessionId,
|
|
1595
|
+
requestId
|
|
1596
|
+
});
|
|
1597
|
+
await sessionEventPublisher.publish(projected);
|
|
1598
|
+
yield projected;
|
|
1599
|
+
}
|
|
1600
|
+
} finally {
|
|
1601
|
+
streamInProgress = false;
|
|
1602
|
+
if (!closed) status = "pending";
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return {
|
|
1606
|
+
get status() {
|
|
1607
|
+
return RuntimeSessionStatusSchema.parse(status);
|
|
1608
|
+
},
|
|
1609
|
+
send(input) {
|
|
1610
|
+
ensureOpen();
|
|
1611
|
+
if (streamInProgress) throw new Error("RUNTIME_SESSION_TURN_IN_PROGRESS");
|
|
1612
|
+
if (pendingInput) throw new Error("RUNTIME_SESSION_INPUT_PENDING");
|
|
1613
|
+
const parsed = RuntimeSessionInputSchema.parse(input);
|
|
1614
|
+
if (abortController.signal.aborted) abortController = new AbortController();
|
|
1615
|
+
pendingInput = parsed;
|
|
1616
|
+
messages.push(parsed);
|
|
1617
|
+
status = "pending";
|
|
1618
|
+
turnId += 1;
|
|
1619
|
+
},
|
|
1620
|
+
async *stream() {
|
|
1621
|
+
for await (const event of executeTurn("legacy")) {
|
|
1622
|
+
yield event;
|
|
1623
|
+
}
|
|
1624
|
+
},
|
|
1625
|
+
async *streamRuntimeEvents() {
|
|
1626
|
+
for await (const event of executeTurn("runtime")) {
|
|
1627
|
+
yield event;
|
|
1628
|
+
}
|
|
1629
|
+
},
|
|
1630
|
+
interrupt() {
|
|
1631
|
+
ensureOpen();
|
|
1632
|
+
abortController.abort();
|
|
1633
|
+
status = "pending";
|
|
1634
|
+
},
|
|
1635
|
+
async close() {
|
|
1636
|
+
if (closed) return;
|
|
1637
|
+
closed = true;
|
|
1638
|
+
abortController.abort();
|
|
1639
|
+
status = "closed";
|
|
1640
|
+
pendingInput = null;
|
|
1641
|
+
}
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
function projectEventToRuntimeEvent(input) {
|
|
1645
|
+
const eventRecord = input.event;
|
|
1646
|
+
const data = isRecord(eventRecord.data) ? eventRecord.data : {};
|
|
1647
|
+
const requestIdFromData = typeof data.requestId === "string" ? data.requestId : void 0;
|
|
1648
|
+
const requestId = requestIdFromData ?? (typeof eventRecord.requestId === "string" ? eventRecord.requestId : void 0) ?? input.requestId;
|
|
1649
|
+
const timestamp = typeof eventRecord.timestamp === "number" && Number.isFinite(eventRecord.timestamp) ? eventRecord.timestamp : void 0;
|
|
1650
|
+
return projectLegacyEventToRuntimeEvent({
|
|
1651
|
+
type: eventRecord.type,
|
|
1652
|
+
sessionId: input.sessionId,
|
|
1653
|
+
requestId,
|
|
1654
|
+
timestamp,
|
|
1655
|
+
data
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
function isRecord(value) {
|
|
1659
|
+
return typeof value === "object" && value !== null;
|
|
1660
|
+
}
|
|
1661
|
+
function resolvePermissionCallbackTimeoutMs(input) {
|
|
1662
|
+
if (typeof input !== "number" || !Number.isFinite(input) || input < 0) {
|
|
1663
|
+
return DEFAULT_PERMISSION_CALLBACK_TIMEOUT_MS;
|
|
1664
|
+
}
|
|
1665
|
+
return Math.floor(input);
|
|
1666
|
+
}
|
|
1667
|
+
async function resolveCallbackDecision(input) {
|
|
1668
|
+
if (!input.permissionPolicy?.canUseTool) return null;
|
|
1669
|
+
try {
|
|
1670
|
+
const callbackPromise = Promise.resolve(input.permissionPolicy.canUseTool(input.payload));
|
|
1671
|
+
return await runWithTimeout(callbackPromise, input.timeoutMs);
|
|
1672
|
+
} catch {
|
|
1673
|
+
return null;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
async function resolvePolicyDecision(input) {
|
|
1677
|
+
try {
|
|
1678
|
+
return await Promise.resolve(input.permissionEvaluator.canUseTool(input.payload));
|
|
1679
|
+
} catch {
|
|
1680
|
+
return null;
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
async function runWithTimeout(promise, timeoutMs) {
|
|
1684
|
+
if (timeoutMs <= 0) return promise;
|
|
1685
|
+
let timeout;
|
|
1686
|
+
try {
|
|
1687
|
+
return await Promise.race([
|
|
1688
|
+
promise,
|
|
1689
|
+
new Promise((_, reject) => {
|
|
1690
|
+
timeout = setTimeout(() => reject(new Error("PERMISSION_CALLBACK_TIMEOUT")), timeoutMs);
|
|
1691
|
+
})
|
|
1692
|
+
]);
|
|
1693
|
+
} finally {
|
|
1694
|
+
if (timeout) clearTimeout(timeout);
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// src/v2/sessionBackend.types.ts
|
|
1699
|
+
var import_zod8 = require("zod");
|
|
1700
|
+
var BackendKindSchema = import_zod8.z.enum(["protocol", "runtime"]);
|
|
1701
|
+
var SessionBackendRouterConfigSchema = import_zod8.z.object({
|
|
1702
|
+
defaultBackend: BackendKindSchema,
|
|
1703
|
+
fallbackBackend: BackendKindSchema.optional(),
|
|
1704
|
+
enableRuntimeBackend: import_zod8.z.boolean().default(false)
|
|
1705
|
+
});
|
|
1706
|
+
var DEFAULT_SESSION_BACKEND_ROUTER_CONFIG = {
|
|
1707
|
+
defaultBackend: "protocol",
|
|
1708
|
+
fallbackBackend: "protocol",
|
|
1709
|
+
enableRuntimeBackend: false
|
|
1710
|
+
};
|
|
1711
|
+
var FallbackTriggerReasonSchema = import_zod8.z.enum([
|
|
1712
|
+
"initialization_failure",
|
|
1713
|
+
"execution_timeout",
|
|
1714
|
+
"error_storm"
|
|
1715
|
+
]);
|
|
1716
|
+
var FALLBACK_TRIGGER_MATRIX = {
|
|
1717
|
+
initialization_failure: true,
|
|
1718
|
+
execution_timeout: true,
|
|
1719
|
+
error_storm: true
|
|
1720
|
+
};
|
|
1721
|
+
var ProtocolErrorCodeSchema = import_zod8.z.enum([
|
|
1722
|
+
"UNKNOWN_ERROR",
|
|
1723
|
+
"NETWORK_ERROR",
|
|
1724
|
+
"TIMEOUT",
|
|
1725
|
+
"SESSION_NOT_FOUND",
|
|
1726
|
+
"PERMISSION_DENIED",
|
|
1727
|
+
"RATE_LIMITED",
|
|
1728
|
+
"VALIDATION_ERROR",
|
|
1729
|
+
"TOOL_EXECUTION_FAILED",
|
|
1730
|
+
"STREAM_DISCONNECTED",
|
|
1731
|
+
"SERVER_UNAVAILABLE"
|
|
1732
|
+
]);
|
|
1733
|
+
var S4_PROTOCOL_ERROR_TOP_CODES = [
|
|
1734
|
+
"UNKNOWN_ERROR",
|
|
1735
|
+
"NETWORK_ERROR",
|
|
1736
|
+
"TIMEOUT",
|
|
1737
|
+
"SESSION_NOT_FOUND",
|
|
1738
|
+
"PERMISSION_DENIED",
|
|
1739
|
+
"RATE_LIMITED",
|
|
1740
|
+
"VALIDATION_ERROR",
|
|
1741
|
+
"TOOL_EXECUTION_FAILED",
|
|
1742
|
+
"STREAM_DISCONNECTED",
|
|
1743
|
+
"SERVER_UNAVAILABLE"
|
|
1744
|
+
];
|
|
1745
|
+
var RuntimeEventErrorTypeSchema = import_zod8.z.enum([
|
|
1746
|
+
"session.error",
|
|
1747
|
+
"session.transport.error",
|
|
1748
|
+
"session.permission.error",
|
|
1749
|
+
"session.tool.error",
|
|
1750
|
+
"session.validation.error",
|
|
1751
|
+
"session.timeout.error"
|
|
1752
|
+
]);
|
|
1753
|
+
var ProtocolErrorMappingSchema = import_zod8.z.record(
|
|
1754
|
+
ProtocolErrorCodeSchema,
|
|
1755
|
+
RuntimeEventErrorTypeSchema
|
|
1756
|
+
);
|
|
1757
|
+
|
|
1758
|
+
// src/v2/protocolSessionBackend.ts
|
|
1759
|
+
var PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE = {
|
|
1760
|
+
UNKNOWN_ERROR: "session.error",
|
|
1761
|
+
NETWORK_ERROR: "session.transport.error",
|
|
1762
|
+
TIMEOUT: "session.timeout.error",
|
|
1763
|
+
SESSION_NOT_FOUND: "session.error",
|
|
1764
|
+
PERMISSION_DENIED: "session.permission.error",
|
|
1765
|
+
RATE_LIMITED: "session.transport.error",
|
|
1766
|
+
VALIDATION_ERROR: "session.validation.error",
|
|
1767
|
+
TOOL_EXECUTION_FAILED: "session.tool.error",
|
|
1768
|
+
STREAM_DISCONNECTED: "session.transport.error",
|
|
1769
|
+
SERVER_UNAVAILABLE: "session.transport.error"
|
|
1770
|
+
};
|
|
1771
|
+
function mapProtocolErrorCodeToRuntimeErrorType(code) {
|
|
1772
|
+
return PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE[code] ?? "session.error";
|
|
1773
|
+
}
|
|
1774
|
+
var ProtocolSessionStreamBindingManager = class {
|
|
1775
|
+
bindings = /* @__PURE__ */ new Map();
|
|
1776
|
+
register(protocolSessionId, sseChannelKey) {
|
|
1777
|
+
const binding = {
|
|
1778
|
+
protocolSessionId,
|
|
1779
|
+
sseChannelKey,
|
|
1780
|
+
createdAt: Date.now()
|
|
1781
|
+
};
|
|
1782
|
+
this.bindings.set(protocolSessionId, binding);
|
|
1783
|
+
return binding;
|
|
1784
|
+
}
|
|
1785
|
+
get(protocolSessionId) {
|
|
1786
|
+
return this.bindings.get(protocolSessionId);
|
|
1787
|
+
}
|
|
1788
|
+
unregister(protocolSessionId) {
|
|
1789
|
+
this.bindings.delete(protocolSessionId);
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
function createProtocolSessionBackend(input) {
|
|
1793
|
+
const pybClient = input?.pybClient ?? new PybClient();
|
|
1794
|
+
const sseClient = input?.sseClient ?? createSSEClient();
|
|
1795
|
+
const bindingManager = new ProtocolSessionStreamBindingManager();
|
|
1796
|
+
return {
|
|
1797
|
+
kind: "protocol",
|
|
1798
|
+
async createSession(config) {
|
|
1799
|
+
const created = await pybClient.session.create(
|
|
1800
|
+
config.createSessionRequest ?? {}
|
|
1801
|
+
);
|
|
1802
|
+
const sessionId = created.sessionId;
|
|
1803
|
+
bindingManager.register(sessionId, sessionId);
|
|
1804
|
+
const legacyQueue = new AsyncEventQueue();
|
|
1805
|
+
const runtimeQueue = new AsyncEventQueue();
|
|
1806
|
+
const unsubscribe = sseClient.subscribeAll((event) => {
|
|
1807
|
+
if (event.sessionId && event.sessionId !== sessionId) return;
|
|
1808
|
+
const legacyEvent = {
|
|
1809
|
+
type: event.type,
|
|
1810
|
+
timestamp: event.timestamp ?? Date.now(),
|
|
1811
|
+
sessionId,
|
|
1812
|
+
data: event.data ?? {}
|
|
1813
|
+
};
|
|
1814
|
+
legacyQueue.push(legacyEvent);
|
|
1815
|
+
runtimeQueue.push(
|
|
1816
|
+
projectLegacyEventToRuntimeEvent({
|
|
1817
|
+
type: legacyEvent.type,
|
|
1818
|
+
sessionId,
|
|
1819
|
+
timestamp: legacyEvent.timestamp,
|
|
1820
|
+
requestId: extractRequestId(legacyEvent.data),
|
|
1821
|
+
data: legacyEvent.data
|
|
1822
|
+
})
|
|
1823
|
+
);
|
|
1824
|
+
});
|
|
1825
|
+
sseClient.connect();
|
|
1826
|
+
let closed = false;
|
|
1827
|
+
return {
|
|
1828
|
+
send(input2) {
|
|
1829
|
+
if (closed) throw new Error("PROTOCOL_BACKEND_SESSION_CLOSED");
|
|
1830
|
+
pybClient.session.prompt(sessionId, {
|
|
1831
|
+
message: input2.message,
|
|
1832
|
+
attachments: input2.attachments,
|
|
1833
|
+
options: { stream: true }
|
|
1834
|
+
}).catch((error) => {
|
|
1835
|
+
const runtimeErrorEvent = toRuntimeErrorEvent(error, sessionId);
|
|
1836
|
+
runtimeQueue.push(runtimeErrorEvent);
|
|
1837
|
+
legacyQueue.push({
|
|
1838
|
+
type: "error",
|
|
1839
|
+
timestamp: Date.now(),
|
|
1840
|
+
sessionId,
|
|
1841
|
+
data: runtimeErrorEvent.data
|
|
1842
|
+
});
|
|
1843
|
+
});
|
|
1844
|
+
},
|
|
1845
|
+
async *stream() {
|
|
1846
|
+
for await (const event of legacyQueue.stream()) {
|
|
1847
|
+
yield event;
|
|
1848
|
+
}
|
|
1849
|
+
},
|
|
1850
|
+
async *streamRuntimeEvents() {
|
|
1851
|
+
for await (const event of runtimeQueue.stream()) {
|
|
1852
|
+
yield event;
|
|
1853
|
+
}
|
|
1854
|
+
},
|
|
1855
|
+
interrupt() {
|
|
1856
|
+
if (closed) return;
|
|
1857
|
+
pybClient.session.abort(sessionId).catch(() => {
|
|
1858
|
+
});
|
|
1859
|
+
},
|
|
1860
|
+
async close() {
|
|
1861
|
+
if (closed) return;
|
|
1862
|
+
closed = true;
|
|
1863
|
+
unsubscribe();
|
|
1864
|
+
sseClient.disconnect();
|
|
1865
|
+
bindingManager.unregister(sessionId);
|
|
1866
|
+
legacyQueue.close();
|
|
1867
|
+
runtimeQueue.close();
|
|
1868
|
+
},
|
|
1869
|
+
status: "pending"
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
var AsyncEventQueue = class {
|
|
1875
|
+
values = [];
|
|
1876
|
+
waits = [];
|
|
1877
|
+
ended = false;
|
|
1878
|
+
push(value) {
|
|
1879
|
+
if (this.ended) return;
|
|
1880
|
+
const wait = this.waits.shift();
|
|
1881
|
+
if (wait) {
|
|
1882
|
+
wait({ value, done: false });
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
this.values.push(value);
|
|
1886
|
+
}
|
|
1887
|
+
close() {
|
|
1888
|
+
this.ended = true;
|
|
1889
|
+
while (this.waits.length > 0) {
|
|
1890
|
+
const wait = this.waits.shift();
|
|
1891
|
+
wait?.({ value: void 0, done: true });
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
async *stream() {
|
|
1895
|
+
while (true) {
|
|
1896
|
+
if (this.values.length > 0) {
|
|
1897
|
+
yield this.values.shift();
|
|
1898
|
+
continue;
|
|
1899
|
+
}
|
|
1900
|
+
if (this.ended) return;
|
|
1901
|
+
const next = await new Promise((resolve) => {
|
|
1902
|
+
this.waits.push(resolve);
|
|
1903
|
+
});
|
|
1904
|
+
if (next.done) return;
|
|
1905
|
+
yield next.value;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
};
|
|
1909
|
+
function extractRequestId(data) {
|
|
1910
|
+
return typeof data.requestId === "string" ? data.requestId : void 0;
|
|
1911
|
+
}
|
|
1912
|
+
function toRuntimeErrorEvent(error, sessionId) {
|
|
1913
|
+
const code = readErrorCode(error);
|
|
1914
|
+
const mappedType = mapProtocolErrorCodeToRuntimeErrorType(code);
|
|
1915
|
+
return projectLegacyEventToRuntimeEvent({
|
|
1916
|
+
type: "error",
|
|
1917
|
+
sessionId,
|
|
1918
|
+
timestamp: Date.now(),
|
|
1919
|
+
data: {
|
|
1920
|
+
code,
|
|
1921
|
+
runtimeErrorType: mappedType,
|
|
1922
|
+
message: readErrorMessage(error),
|
|
1923
|
+
recoverable: mappedType !== "session.validation.error"
|
|
1924
|
+
}
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
function readErrorCode(error) {
|
|
1928
|
+
if (isRecord2(error) && typeof error.code === "string") {
|
|
1929
|
+
const matched = error.code;
|
|
1930
|
+
if (matched in PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE) return matched;
|
|
1931
|
+
}
|
|
1932
|
+
return "UNKNOWN_ERROR";
|
|
1933
|
+
}
|
|
1934
|
+
function readErrorMessage(error) {
|
|
1935
|
+
if (error instanceof Error) return error.message;
|
|
1936
|
+
if (isRecord2(error) && typeof error.message === "string") return error.message;
|
|
1937
|
+
return "protocol backend session error";
|
|
1938
|
+
}
|
|
1939
|
+
function isRecord2(value) {
|
|
1940
|
+
return typeof value === "object" && value !== null;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
// src/v2/runtimeSessionBackend.ts
|
|
1944
|
+
function createRuntimeSessionBackend(input) {
|
|
1945
|
+
const createSessionImpl = input?.createRuntimeSession ?? createRuntimeSession;
|
|
1946
|
+
return {
|
|
1947
|
+
kind: "runtime",
|
|
1948
|
+
async createSession(config) {
|
|
1949
|
+
const sessionId = resolveSessionId(config);
|
|
1950
|
+
const runtimeSessionConfig = resolveRuntimeSessionConfig(config);
|
|
1951
|
+
let runtimeSession;
|
|
1952
|
+
try {
|
|
1953
|
+
runtimeSession = createSessionImpl({
|
|
1954
|
+
sessionId,
|
|
1955
|
+
...runtimeSessionConfig
|
|
1956
|
+
});
|
|
1957
|
+
} catch (error) {
|
|
1958
|
+
throw toRuntimeBackendInitializationError({
|
|
1959
|
+
event: mapRuntimeBackendErrorToRuntimeEvent({
|
|
1960
|
+
error,
|
|
1961
|
+
sessionId,
|
|
1962
|
+
phase: "initialization"
|
|
1963
|
+
})
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
let closed = false;
|
|
1967
|
+
return {
|
|
1968
|
+
send(input2) {
|
|
1969
|
+
if (closed) throw new Error("RUNTIME_BACKEND_SESSION_CLOSED");
|
|
1970
|
+
runtimeSession.send(input2);
|
|
1971
|
+
},
|
|
1972
|
+
async *stream() {
|
|
1973
|
+
try {
|
|
1974
|
+
for await (const event of runtimeSession.stream()) {
|
|
1975
|
+
yield {
|
|
1976
|
+
type: event.type,
|
|
1977
|
+
timestamp: Date.now(),
|
|
1978
|
+
sessionId,
|
|
1979
|
+
data: withBackendSource(event.data)
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
const runtimeError = mapRuntimeBackendErrorToRuntimeEvent({
|
|
1984
|
+
error,
|
|
1985
|
+
sessionId,
|
|
1986
|
+
phase: "execution"
|
|
1987
|
+
});
|
|
1988
|
+
yield {
|
|
1989
|
+
type: "error",
|
|
1990
|
+
timestamp: runtimeError.timestamp,
|
|
1991
|
+
sessionId,
|
|
1992
|
+
data: runtimeError.data
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
},
|
|
1996
|
+
async *streamRuntimeEvents() {
|
|
1997
|
+
try {
|
|
1998
|
+
for await (const event of runtimeSession.streamRuntimeEvents()) {
|
|
1999
|
+
yield withRuntimeBackendSource(event);
|
|
2000
|
+
}
|
|
2001
|
+
} catch (error) {
|
|
2002
|
+
yield mapRuntimeBackendErrorToRuntimeEvent({
|
|
2003
|
+
error,
|
|
2004
|
+
sessionId,
|
|
2005
|
+
phase: "execution"
|
|
2006
|
+
});
|
|
2007
|
+
}
|
|
2008
|
+
},
|
|
2009
|
+
interrupt() {
|
|
2010
|
+
if (closed) return;
|
|
2011
|
+
runtimeSession.interrupt();
|
|
2012
|
+
},
|
|
2013
|
+
async close() {
|
|
2014
|
+
if (closed) return;
|
|
2015
|
+
closed = true;
|
|
2016
|
+
await runtimeSession.close();
|
|
2017
|
+
},
|
|
2018
|
+
status: runtimeSession.status
|
|
2019
|
+
};
|
|
2020
|
+
}
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
function mapRuntimeBackendErrorToRuntimeEvent(input) {
|
|
2024
|
+
return {
|
|
2025
|
+
domain: "session",
|
|
2026
|
+
type: "session.error",
|
|
2027
|
+
sessionId: input.sessionId,
|
|
2028
|
+
timestamp: Date.now(),
|
|
2029
|
+
data: {
|
|
2030
|
+
backendSource: "runtime",
|
|
2031
|
+
phase: input.phase,
|
|
2032
|
+
message: readErrorMessage2(input.error),
|
|
2033
|
+
recoverable: input.phase !== "initialization"
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
}
|
|
2037
|
+
function withRuntimeBackendSource(event) {
|
|
2038
|
+
const eventRecord = event;
|
|
2039
|
+
return {
|
|
2040
|
+
...event,
|
|
2041
|
+
data: withBackendSource(eventRecord.data)
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
function withBackendSource(data) {
|
|
2045
|
+
if (!isRecord3(data)) return { backendSource: "runtime" };
|
|
2046
|
+
return { ...data, backendSource: "runtime" };
|
|
2047
|
+
}
|
|
2048
|
+
function resolveSessionId(config) {
|
|
2049
|
+
if (typeof config.sessionId === "string" && config.sessionId.length > 0) {
|
|
2050
|
+
return config.sessionId;
|
|
2051
|
+
}
|
|
2052
|
+
return `runtime-${Date.now()}`;
|
|
2053
|
+
}
|
|
2054
|
+
function resolveRuntimeSessionConfig(config) {
|
|
2055
|
+
const candidate = config.runtimeSessionConfig;
|
|
2056
|
+
if (!isRecord3(candidate)) return {};
|
|
2057
|
+
return candidate;
|
|
2058
|
+
}
|
|
2059
|
+
function toRuntimeBackendInitializationError(input) {
|
|
2060
|
+
const error = new Error("RUNTIME_BACKEND_SESSION_INIT_FAILED");
|
|
2061
|
+
error.runtimeEvent = input.event;
|
|
2062
|
+
return error;
|
|
2063
|
+
}
|
|
2064
|
+
function readErrorMessage2(error) {
|
|
2065
|
+
if (error instanceof Error) return error.message;
|
|
2066
|
+
if (isRecord3(error) && typeof error.message === "string") return error.message;
|
|
2067
|
+
return "runtime backend session error";
|
|
2068
|
+
}
|
|
2069
|
+
function isRecord3(value) {
|
|
2070
|
+
return typeof value === "object" && value !== null;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// src/v2/sessionBackendConfig.ts
|
|
2074
|
+
var SESSION_BACKEND_CONFIG_CONTRACT_VERSION = "s5-a0";
|
|
2075
|
+
var SESSION_BACKEND_ENV_KEY = "PYB_DEFAULT_BACKEND";
|
|
2076
|
+
var SESSION_BACKEND_OBSERVABILITY_SPEC = {
|
|
2077
|
+
backendSource: ["default", "env_config", "file_config", "user_explicit", "fallback"],
|
|
2078
|
+
fallbackReason: ["initialization_failure", "execution_timeout", "error_storm"],
|
|
2079
|
+
routeSource: ["default", "env_config", "user_explicit"]
|
|
2080
|
+
};
|
|
2081
|
+
var S5_A0_EQUIVALENCE_SAMPLE_SET = [
|
|
2082
|
+
{
|
|
2083
|
+
id: "EQU-001",
|
|
2084
|
+
scenario: "\u666E\u901A\u5BF9\u8BDD\u8F6E\u6B21",
|
|
2085
|
+
assertions: ["\u6D88\u606F\u5185\u5BB9\u4E00\u81F4", "\u4E8B\u4EF6\u5E8F\u5217\u4E00\u81F4", "\u72B6\u6001\u53D8\u5316\u4E00\u81F4"]
|
|
2086
|
+
},
|
|
2087
|
+
{
|
|
2088
|
+
id: "EQU-002",
|
|
2089
|
+
scenario: "\u5DE5\u5177\u8C03\u7528\u8F6E\u6B21",
|
|
2090
|
+
assertions: ["\u5DE5\u5177\u6267\u884C\u7ED3\u679C\u4E00\u81F4", "\u4E8B\u4EF6\u5E8F\u5217\u4E00\u81F4"]
|
|
2091
|
+
},
|
|
2092
|
+
{
|
|
2093
|
+
id: "EQU-003",
|
|
2094
|
+
scenario: "\u6743\u9650\u62D2\u7EDD\u8F6E\u6B21",
|
|
2095
|
+
assertions: ["\u62D2\u7EDD\u539F\u56E0\u4E00\u81F4", "\u4E8B\u4EF6\u5E8F\u5217\u4E00\u81F4"]
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
id: "EQU-004",
|
|
2099
|
+
scenario: "\u4E2D\u65AD\u4E0E\u6062\u590D\u8F6E\u6B21",
|
|
2100
|
+
assertions: ["\u4E2D\u65AD\u884C\u4E3A\u4E00\u81F4", "\u6062\u590D\u540E\u72B6\u6001\u4E00\u81F4"]
|
|
2101
|
+
},
|
|
2102
|
+
{
|
|
2103
|
+
id: "EQU-005",
|
|
2104
|
+
scenario: "\u9519\u8BEF\u5904\u7406\u8F6E\u6B21",
|
|
2105
|
+
assertions: ["\u9519\u8BEF\u4E8B\u4EF6\u4E00\u81F4", "\u72B6\u6001\u53D8\u5316\u4E00\u81F4"]
|
|
2106
|
+
},
|
|
2107
|
+
{
|
|
2108
|
+
id: "EQU-006",
|
|
2109
|
+
scenario: "\u591A\u8F6E\u5BF9\u8BDD",
|
|
2110
|
+
assertions: ["\u6D88\u606F\u5386\u53F2\u4E00\u81F4", "\u4E0A\u4E0B\u6587\u4FDD\u6301\u4E00\u81F4"]
|
|
2111
|
+
}
|
|
2112
|
+
];
|
|
2113
|
+
function emitBackendConfigWarning(value, emitWarning = console.warn) {
|
|
2114
|
+
emitWarning(
|
|
2115
|
+
`[sdk-session-backend-config] Invalid ${SESSION_BACKEND_ENV_KEY} value "${String(
|
|
2116
|
+
value
|
|
2117
|
+
)}", fallback to "runtime".`
|
|
2118
|
+
);
|
|
2119
|
+
}
|
|
2120
|
+
function resolveDefaultBackend(config, input) {
|
|
2121
|
+
const value = config?.PYB_DEFAULT_BACKEND;
|
|
2122
|
+
if (value === "protocol" || value === "runtime") return value;
|
|
2123
|
+
if (value !== void 0) {
|
|
2124
|
+
emitBackendConfigWarning(value, input?.emitWarning);
|
|
2125
|
+
}
|
|
2126
|
+
return "runtime";
|
|
2127
|
+
}
|
|
2128
|
+
function resolveDefaultBackendFromEnv(input) {
|
|
2129
|
+
const env = input?.env ?? process.env;
|
|
2130
|
+
const envValue = env[SESSION_BACKEND_ENV_KEY];
|
|
2131
|
+
const defaultBackend = resolveDefaultBackend(
|
|
2132
|
+
envValue === void 0 ? void 0 : { PYB_DEFAULT_BACKEND: envValue },
|
|
2133
|
+
{ emitWarning: input?.emitWarning }
|
|
2134
|
+
);
|
|
2135
|
+
return {
|
|
2136
|
+
defaultBackend,
|
|
2137
|
+
routeSource: envValue === "protocol" || envValue === "runtime" ? "env_config" : "default"
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
// src/v2/sessionBackendRouter.ts
|
|
2142
|
+
function createSessionBackendRouter(input) {
|
|
2143
|
+
const resolvedFromEnv = resolveDefaultBackendFromEnv({
|
|
2144
|
+
env: input.env,
|
|
2145
|
+
emitWarning: input.emitWarning
|
|
2146
|
+
});
|
|
2147
|
+
const routerConfig = SessionBackendRouterConfigSchema.parse({
|
|
2148
|
+
...DEFAULT_SESSION_BACKEND_ROUTER_CONFIG,
|
|
2149
|
+
defaultBackend: resolvedFromEnv.defaultBackend,
|
|
2150
|
+
enableRuntimeBackend: true,
|
|
2151
|
+
...input.routerConfig ?? {}
|
|
2152
|
+
});
|
|
2153
|
+
return {
|
|
2154
|
+
kind: resolveRouterBackendKind({
|
|
2155
|
+
preferredBackend: void 0,
|
|
2156
|
+
config: routerConfig
|
|
2157
|
+
}),
|
|
2158
|
+
async createSession(config) {
|
|
2159
|
+
const preferred = readPreferredBackend(config);
|
|
2160
|
+
const routeSource = resolveRouteSource({
|
|
2161
|
+
preferredBackend: preferred,
|
|
2162
|
+
envRouteSource: resolvedFromEnv.routeSource
|
|
2163
|
+
});
|
|
2164
|
+
const primaryKind = resolveRouterBackendKind({
|
|
2165
|
+
preferredBackend: preferred,
|
|
2166
|
+
config: routerConfig
|
|
2167
|
+
});
|
|
2168
|
+
const fallbackKind = primaryKind === routerConfig.fallbackBackend ? void 0 : routerConfig.fallbackBackend;
|
|
2169
|
+
let currentBackendKind = primaryKind;
|
|
2170
|
+
let fallbackReason;
|
|
2171
|
+
let pendingFallbackReason;
|
|
2172
|
+
let continuousSendErrors = 0;
|
|
2173
|
+
let currentSession;
|
|
2174
|
+
try {
|
|
2175
|
+
currentSession = await resolveBackend(input, primaryKind).createSession(config);
|
|
2176
|
+
} catch (error) {
|
|
2177
|
+
if (!fallbackKind || !shouldTriggerFallback("initialization_failure")) throw error;
|
|
2178
|
+
currentSession = await resolveBackend(input, fallbackKind).createSession(config);
|
|
2179
|
+
currentBackendKind = fallbackKind;
|
|
2180
|
+
fallbackReason = "initialization_failure";
|
|
2181
|
+
}
|
|
2182
|
+
async function activateFallback(reason) {
|
|
2183
|
+
if (!fallbackKind || !shouldTriggerFallback(reason)) {
|
|
2184
|
+
throw new Error(`FALLBACK_NOT_AVAILABLE:${reason}`);
|
|
2185
|
+
}
|
|
2186
|
+
currentSession = await resolveBackend(input, fallbackKind).createSession(config);
|
|
2187
|
+
currentBackendKind = fallbackKind;
|
|
2188
|
+
fallbackReason = reason;
|
|
2189
|
+
pendingFallbackReason = void 0;
|
|
2190
|
+
continuousSendErrors = 0;
|
|
2191
|
+
}
|
|
2192
|
+
async function ensureFallbackActivatedIfNeeded() {
|
|
2193
|
+
if (!pendingFallbackReason) return;
|
|
2194
|
+
await activateFallback(pendingFallbackReason);
|
|
2195
|
+
}
|
|
2196
|
+
function buildRuntimeEvent(event) {
|
|
2197
|
+
return injectRoutingMetaToRuntimeEvent(event, {
|
|
2198
|
+
backendSource: currentBackendKind,
|
|
2199
|
+
routeSource,
|
|
2200
|
+
fallbackReason
|
|
2201
|
+
});
|
|
2202
|
+
}
|
|
2203
|
+
function buildLegacyEvent(event) {
|
|
2204
|
+
return injectRoutingMetaToLegacyEvent(event, {
|
|
2205
|
+
backendSource: currentBackendKind,
|
|
2206
|
+
routeSource,
|
|
2207
|
+
fallbackReason
|
|
2208
|
+
});
|
|
2209
|
+
}
|
|
2210
|
+
return {
|
|
2211
|
+
send(inputValue) {
|
|
2212
|
+
if (pendingFallbackReason) return;
|
|
2213
|
+
try {
|
|
2214
|
+
currentSession.send(inputValue);
|
|
2215
|
+
continuousSendErrors = 0;
|
|
2216
|
+
return;
|
|
2217
|
+
} catch (error) {
|
|
2218
|
+
if (isTimeoutError(error)) {
|
|
2219
|
+
pendingFallbackReason = "execution_timeout";
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
continuousSendErrors += 1;
|
|
2223
|
+
if (continuousSendErrors >= 3) {
|
|
2224
|
+
pendingFallbackReason = "error_storm";
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
throw error;
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
async *stream() {
|
|
2231
|
+
await ensureFallbackActivatedIfNeeded();
|
|
2232
|
+
for await (const event of currentSession.stream()) {
|
|
2233
|
+
yield buildLegacyEvent(event);
|
|
2234
|
+
}
|
|
2235
|
+
},
|
|
2236
|
+
async *streamRuntimeEvents() {
|
|
2237
|
+
await ensureFallbackActivatedIfNeeded();
|
|
2238
|
+
if (currentSession.streamRuntimeEvents) {
|
|
2239
|
+
for await (const event of currentSession.streamRuntimeEvents()) {
|
|
2240
|
+
yield buildRuntimeEvent(event);
|
|
2241
|
+
}
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
for await (const event of currentSession.stream()) {
|
|
2245
|
+
yield buildRuntimeEvent(projectLegacyEventToRuntimeEvent(toProjectableLegacyEvent(event)));
|
|
2246
|
+
}
|
|
2247
|
+
},
|
|
2248
|
+
interrupt() {
|
|
2249
|
+
currentSession.interrupt();
|
|
2250
|
+
},
|
|
2251
|
+
async close() {
|
|
2252
|
+
await currentSession.close();
|
|
2253
|
+
},
|
|
2254
|
+
get status() {
|
|
2255
|
+
return currentSession.status;
|
|
2256
|
+
}
|
|
2257
|
+
};
|
|
2258
|
+
}
|
|
2259
|
+
};
|
|
2260
|
+
}
|
|
2261
|
+
function shouldTriggerFallback(reason) {
|
|
2262
|
+
return FALLBACK_TRIGGER_MATRIX[reason] === true;
|
|
2263
|
+
}
|
|
2264
|
+
function resolveRouterBackendKind(input) {
|
|
2265
|
+
const preferred = input.preferredBackend ?? input.config.defaultBackend;
|
|
2266
|
+
if (preferred === "runtime" && !input.config.enableRuntimeBackend) return "protocol";
|
|
2267
|
+
return preferred;
|
|
2268
|
+
}
|
|
2269
|
+
function resolveBackend(input, kind) {
|
|
2270
|
+
if (kind === "protocol") return input.protocolBackend;
|
|
2271
|
+
if (!input.runtimeBackend) throw new Error("RUNTIME_BACKEND_NOT_AVAILABLE");
|
|
2272
|
+
return input.runtimeBackend;
|
|
2273
|
+
}
|
|
2274
|
+
function readPreferredBackend(config) {
|
|
2275
|
+
if (config.preferredBackend === "protocol") return "protocol";
|
|
2276
|
+
if (config.preferredBackend === "runtime") return "runtime";
|
|
2277
|
+
return void 0;
|
|
2278
|
+
}
|
|
2279
|
+
function resolveRouteSource(input) {
|
|
2280
|
+
if (input.preferredBackend) return "user_explicit";
|
|
2281
|
+
if (input.envRouteSource === "env_config") return "env_config";
|
|
2282
|
+
return "default";
|
|
2283
|
+
}
|
|
2284
|
+
function injectRoutingMetaToLegacyEvent(event, input) {
|
|
2285
|
+
const data = isRecord4(event.data) ? event.data : {};
|
|
2286
|
+
return {
|
|
2287
|
+
...event,
|
|
2288
|
+
data: {
|
|
2289
|
+
...data,
|
|
2290
|
+
backendSource: input.backendSource,
|
|
2291
|
+
routeSource: input.routeSource,
|
|
2292
|
+
...input.fallbackReason ? { fallbackReason: input.fallbackReason } : {}
|
|
2293
|
+
}
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
function injectRoutingMetaToRuntimeEvent(event, input) {
|
|
2297
|
+
const data = isRecord4(event.data) ? event.data : {};
|
|
2298
|
+
return {
|
|
2299
|
+
...event,
|
|
2300
|
+
data: {
|
|
2301
|
+
...data,
|
|
2302
|
+
backendSource: input.backendSource,
|
|
2303
|
+
routeSource: input.routeSource,
|
|
2304
|
+
...input.fallbackReason ? { fallbackReason: input.fallbackReason } : {}
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2307
|
+
}
|
|
2308
|
+
function isTimeoutError(error) {
|
|
2309
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2310
|
+
return message.toLowerCase().includes("timeout");
|
|
2311
|
+
}
|
|
2312
|
+
function toProjectableLegacyEvent(input) {
|
|
2313
|
+
const data = isRecord4(input.data) ? input.data : {};
|
|
2314
|
+
const type = typeof input.type === "string" ? input.type : "unknown";
|
|
2315
|
+
const sessionId = typeof input.sessionId === "string" ? input.sessionId : typeof data.sessionId === "string" ? data.sessionId : "unknown-session";
|
|
2316
|
+
const requestId = typeof input.requestId === "string" ? input.requestId : typeof data.requestId === "string" ? data.requestId : void 0;
|
|
2317
|
+
const timestamp = typeof input.timestamp === "number" ? input.timestamp : void 0;
|
|
2318
|
+
return {
|
|
2319
|
+
type,
|
|
2320
|
+
sessionId,
|
|
2321
|
+
requestId,
|
|
2322
|
+
timestamp,
|
|
2323
|
+
data
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2326
|
+
function isRecord4(value) {
|
|
2327
|
+
return typeof value === "object" && value !== null;
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
// src/index.ts
|
|
2331
|
+
var SDK_VERSION = "0.1.0";
|
|
2332
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2333
|
+
0 && (module.exports = {
|
|
2334
|
+
BackendKindSchema,
|
|
2335
|
+
ContentBlockSchema,
|
|
2336
|
+
DEFAULT_SESSION_BACKEND_ROUTER_CONFIG,
|
|
2337
|
+
DualTrackMetricsSchema,
|
|
2338
|
+
DualTrackRawStatsSchema,
|
|
2339
|
+
DualTrackThresholdsSchema,
|
|
2340
|
+
ErrorEventSchema,
|
|
2341
|
+
ErrorStreamEventSchema,
|
|
2342
|
+
FALLBACK_TRIGGER_MATRIX,
|
|
2343
|
+
FallbackTriggerReasonSchema,
|
|
2344
|
+
MessageCompletedEventSchema,
|
|
2345
|
+
MessageCreatedEventSchema,
|
|
2346
|
+
MessageSchema,
|
|
2347
|
+
MessageUpdatedEventSchema,
|
|
2348
|
+
PROTOCOL_ERROR_TO_RUNTIME_ERROR_TYPE,
|
|
2349
|
+
PermissionRequestedEventSchema,
|
|
2350
|
+
PermissionRespondedEventSchema,
|
|
2351
|
+
PermissionTimeoutEventSchema,
|
|
2352
|
+
ProtocolErrorCodeSchema,
|
|
2353
|
+
ProtocolErrorMappingSchema,
|
|
2354
|
+
ProtocolSessionStreamBindingManager,
|
|
2355
|
+
PybClient,
|
|
2356
|
+
PybSSEEventSchema,
|
|
2357
|
+
RequestCompletedEventSchema,
|
|
2358
|
+
RequestStartedEventSchema,
|
|
2359
|
+
RuntimeEventDomainSchema,
|
|
2360
|
+
RuntimeEventErrorTypeSchema,
|
|
2361
|
+
RuntimeEventSchema,
|
|
2362
|
+
RuntimeSessionEventSchema,
|
|
2363
|
+
RuntimeSessionInputSchema,
|
|
2364
|
+
RuntimeSessionStatusSchema,
|
|
2365
|
+
S4_PROTOCOL_ERROR_TOP_CODES,
|
|
2366
|
+
S5_A0_EQUIVALENCE_SAMPLE_SET,
|
|
2367
|
+
SDK_VERSION,
|
|
2368
|
+
SESSION_BACKEND_CONFIG_CONTRACT_VERSION,
|
|
2369
|
+
SESSION_BACKEND_ENV_KEY,
|
|
2370
|
+
SESSION_BACKEND_OBSERVABILITY_SPEC,
|
|
2371
|
+
SSEClient,
|
|
2372
|
+
SSEDedupEventSchema,
|
|
2373
|
+
SSEReplayEventSchema,
|
|
2374
|
+
SSEReplayGapEventSchema,
|
|
2375
|
+
ServerConnectedEventSchema,
|
|
2376
|
+
ServerHeartbeatEventSchema,
|
|
2377
|
+
ServerStatusEventSchema,
|
|
2378
|
+
SessionBackendRouterConfigSchema,
|
|
2379
|
+
SessionCreatedEventSchema,
|
|
2380
|
+
SessionDeletedEventSchema,
|
|
2381
|
+
SessionUpdatedEventSchema,
|
|
2382
|
+
ToolCompletedEventSchema,
|
|
2383
|
+
ToolErrorEventSchema,
|
|
2384
|
+
ToolProgressEventSchema,
|
|
2385
|
+
ToolStartedEventSchema,
|
|
2386
|
+
V2MessageSchema,
|
|
2387
|
+
V2RequestStatusSchema,
|
|
2388
|
+
V2SessionSchema,
|
|
2389
|
+
V2SessionStatusSchema,
|
|
2390
|
+
V2ToolUseContextSchema,
|
|
2391
|
+
buildDefaultDualTrackThresholds,
|
|
2392
|
+
buildV2ToolUseContextFromPromptRequest,
|
|
2393
|
+
canTransitionV2SessionStatus,
|
|
2394
|
+
createDefaultToolPermissionContextForSdk,
|
|
2395
|
+
createProtocolSessionBackend,
|
|
2396
|
+
createRuntimePermissionContextForSession,
|
|
2397
|
+
createRuntimeSession,
|
|
2398
|
+
createRuntimeSessionBackend,
|
|
2399
|
+
createSSEClient,
|
|
2400
|
+
createSessionBackendRouter,
|
|
2401
|
+
emitBackendConfigWarning,
|
|
2402
|
+
evaluateDualTrackMetrics,
|
|
2403
|
+
evaluateV1DeprecationReadiness,
|
|
2404
|
+
getRuntimeEventMappingRules,
|
|
2405
|
+
isToolAutoExecutableInContext,
|
|
2406
|
+
mapProtocolErrorCodeToRuntimeErrorType,
|
|
2407
|
+
mapRuntimeBackendErrorToRuntimeEvent,
|
|
2408
|
+
mapRuntimeMessageToV2,
|
|
2409
|
+
mapRuntimeSessionStatusToV2,
|
|
2410
|
+
mapV1MessageToV2,
|
|
2411
|
+
mapV1SessionStatusToV2,
|
|
2412
|
+
projectLegacyEventToRuntimeEvent,
|
|
2413
|
+
projectRuntimeEventToLegacyEvent,
|
|
2414
|
+
resolveDefaultBackend,
|
|
2415
|
+
resolveDefaultBackendFromEnv,
|
|
2416
|
+
resolvePermissionDecision,
|
|
2417
|
+
resolvePermissionModeForSdk,
|
|
2418
|
+
resolveRouterBackendKind,
|
|
2419
|
+
shouldTriggerFallback,
|
|
2420
|
+
validateV2Message,
|
|
2421
|
+
validateV2Session,
|
|
2422
|
+
validateV2ToolUseContext
|
|
2423
|
+
});
|