@rivus/agent 0.13.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +20 -15
  2. package/dist/acp.d.ts +40 -40
  3. package/dist/acp.js +71 -31
  4. package/dist/bootstrap/pi-feishu.d.ts +20 -0
  5. package/dist/bootstrap/pi-feishu.js +594 -0
  6. package/dist/{agent-loop.d.ts → chunks/agent-loop.d.ts} +293 -44
  7. package/dist/chunks/agent-loop.js +1272 -0
  8. package/dist/chunks/api.d.ts +70 -0
  9. package/dist/chunks/api.js +471 -0
  10. package/dist/{rivus-plugin.d.ts → chunks/api2.d.ts} +271 -120
  11. package/dist/chunks/api2.js +1331 -0
  12. package/dist/chunks/api3.d.ts +402 -0
  13. package/dist/chunks/index.d.ts +3662 -0
  14. package/dist/chunks/module.js +267 -0
  15. package/dist/chunks/pi-skill-tool.js +460 -0
  16. package/dist/chunks/pi-tool-proxy.d.ts +188 -0
  17. package/dist/chunks/pi.js +329 -0
  18. package/dist/{rivus-daemon-cli.js → chunks/rivus-daemon-cli.js} +2197 -1526
  19. package/dist/{rivus-plugin-testkit.d.ts → chunks/rivus-plugin-testkit.d.ts} +1 -1
  20. package/dist/{rivus-plugin-testkit.js → chunks/rivus-plugin-testkit.js} +11 -3
  21. package/dist/chunks/sha256-digest.js +12 -0
  22. package/dist/chunks/spi.d.ts +1 -0
  23. package/dist/chunks/spi.js +2 -0
  24. package/dist/chunks/src.js +9897 -0
  25. package/dist/cli.js +602 -93
  26. package/dist/index.d.ts +8 -3645
  27. package/dist/index.js +9 -10483
  28. package/dist/mcp.d.ts +3 -38
  29. package/dist/mcp.js +4 -114
  30. package/dist/pi.d.ts +95 -9
  31. package/dist/pi.js +3 -146
  32. package/dist/testing/index.d.ts +1 -1
  33. package/dist/testing/index.js +1 -1
  34. package/examples/pi-feishu-deployment.bootstrap.ts +35 -46
  35. package/examples/pi-feishu.bootstrap.ts +35 -20
  36. package/examples/rivus-starter.plugin.mjs +3 -1
  37. package/package.json +8 -2
  38. package/dist/agent-loop.js +0 -121
  39. package/dist/agent-memory.d.ts +0 -100
  40. package/dist/agent-memory.js +0 -114
  41. package/dist/background-session-authority.js +0 -224
  42. package/dist/background-session-input.js +0 -45
  43. package/dist/background-session-service.d.ts +0 -291
  44. package/dist/pi-tool-proxy.d.ts +0 -197
  45. package/dist/rivus-plugin-registry.js +0 -215
  46. package/dist/tool-input-digest.js +0 -128
@@ -0,0 +1,594 @@
1
+ import { $ as createFeishuPresentationPreparation, $n as createUuidRunIds, B as openJsonlBackgroundSessionDeliveryStore, D as openJsonAutomationTickRepository, F as createRivusMemoryToolDescriptor, Gt as createConfiguredFeishuTextReplySender, Ht as createFeishuTopicContextResolver, Kt as createConfiguredFeishuCardRolloverRuntime, L as createConfiguredFeishuBackgroundSessionDelivery, Mt as createLangfuseAgentTelemetry, N as createProjectMemoryPromptPreparer, Nt as resolveLangfuseTelemetryConfig, O as createScheduledAutomation, Ot as createPiSessionRegistry, Qn as createSystemClock, R as resolveFeishuDeliveryChatId, Rt as createJsonlAgentEventLog, Tt as AUTOMATION_SUPPRESSION_PREFIX, U as openJsonlBackgroundSessionRepository, Vn as mergePiProviderBaseUrlOverride, W as createBackgroundSessionHostTools, _r as openJsonlFeishuCardDeliveryLedger, ar as createJsonFetchRequest, at as openJsonlToolOperationLedger, c as createHumanInteractionToolApprovalGateway, cr as createSessionScheduler, dr as openJsonlFeishuInboxRepository, et as createFeishuDeploymentEndpoint, fn as createLazyFeishuWebSocketEventDispatcher, ir as createAgentHarness, it as openJsonlRecoveryControl, j as openJsonlAgentMemoryService, kt as createPiAgentLoop, l as createRoutedHumanInteractionToolApprovalService, lr as openJsonFeishuSessionStore, m as loadRivusDeploymentManifest, o as createConfiguredFeishuAutomationCardSender, ot as createToolBroker, pt as createFeishuCotPublisher, r as createJsonlHumanInteractionRepository, rn as createConfiguredFeishuOpenApiClient, s as createHumanInteractionEndpointRegistry, st as createAgentsMdInstructionsProvider, t as createConfiguredFeishuHumanInteractionPresenter, tt as createAgentHarnessPooledRuntime, u as createHumanInteractionService, wt as readAutomationPresentation, yr as createFeishuCardDeliveryReconciler, yt as createJsonFileFeishuCardTargetRegistry } from "../chunks/src.js";
2
+ import { V as resolveFeishuEndpointCredentials, a as createWorkspaceRootHandle } from "../chunks/rivus-daemon-cli.js";
3
+ import { n as createPiSkillRuntime } from "../chunks/pi-skill-tool.js";
4
+ import { $ as createBackgroundSessionStepSourceMessageId, f as createBackgroundSessionService, t as createBackgroundSessionSupervisor, u as resolveBackgroundSessionSupervisorIntervalMs } from "../chunks/api2.js";
5
+ import { i as resolvePiSessionToolNames, l as validatePiSkillCommand, n as createPiToolProxyDefinitions, p as createPiSkillReadTools, r as createPiSessionResources, t as createPiToolNameResolver } from "../chunks/pi.js";
6
+ import { Effect } from "effect";
7
+ import { createHash, randomUUID } from "node:crypto";
8
+ import { mkdir, readFile } from "node:fs/promises";
9
+ import { join, relative } from "node:path";
10
+ import { homedir } from "node:os";
11
+ import * as Lark from "@larksuiteoapi/node-sdk";
12
+ import { AuthStorage, ModelRegistry, SessionManager, createAgentSession } from "@earendil-works/pi-coding-agent";
13
+ //#region examples/pi-feishu-deployment.bootstrap.ts
14
+ const STATE_DIR = process.env.RIVUS_DEPLOYMENT_STATE_DIR?.trim() || ".rivus/deployment";
15
+ const PI_AGENT_DIR = join(STATE_DIR, "pi-agent");
16
+ const PI_AUTH_FILE = join(STATE_DIR, "pi-auth.json");
17
+ const PI_MODELS_FILE = join(STATE_DIR, "pi-models.json");
18
+ const THINKING_LEVELS = /* @__PURE__ */ new Set([
19
+ "off",
20
+ "minimal",
21
+ "low",
22
+ "medium",
23
+ "high",
24
+ "xhigh"
25
+ ]);
26
+ async function createRivusDeploymentAdapters(context) {
27
+ await mkdir(PI_AGENT_DIR, { recursive: true });
28
+ const piOptions = await createPiSessionOptions(context);
29
+ const telemetryConfig = resolveLangfuseTelemetryConfig(context.env);
30
+ const telemetry = telemetryConfig ? createLangfuseAgentTelemetry(telemetryConfig) : void 0;
31
+ const memory = await openJsonlAgentMemoryService({ filePath: join(STATE_DIR, "memory", "agent-memory.jsonl") });
32
+ const memoryTenantId = context.env.RIVUS_MEMORY_TENANT_ID?.trim() || "local";
33
+ const request = createJsonFetchRequest();
34
+ const createOpenApiClient = (config) => createConfiguredFeishuOpenApiClient({
35
+ config,
36
+ request: (input) => request(input).pipe(Effect.map((response) => response))
37
+ });
38
+ const interactionRegistry = createHumanInteractionEndpointRegistry();
39
+ const manifest = await loadRivusDeploymentManifest(context.manifestPath);
40
+ const backgroundSessionsConfig = manifest.backgroundSessions;
41
+ const sessionRepository = backgroundSessionsConfig?.enabled ? await openJsonlBackgroundSessionRepository({ filePath: join(STATE_DIR, "background-sessions", "sessions.jsonl") }) : void 0;
42
+ const sessionDeliveries = backgroundSessionsConfig?.enabled ? await openJsonlBackgroundSessionDeliveryStore({ filePath: join(STATE_DIR, "background-sessions", "deliveries.jsonl") }) : void 0;
43
+ const deliveryClients = /* @__PURE__ */ new Map();
44
+ const backgroundService = backgroundSessionsConfig?.enabled ? createBackgroundSessionService({
45
+ clock: { now: () => (/* @__PURE__ */ new Date()).toISOString() },
46
+ deliveries: sessionDeliveries,
47
+ repository: sessionRepository
48
+ }) : void 0;
49
+ const createBackgroundSessionAdapter = (input) => {
50
+ const resolveDeliverySender = async (endpointId) => {
51
+ const existing = deliveryClients.get(endpointId);
52
+ if (existing) return existing;
53
+ const endpoint = manifest.endpoints.find(({ id }) => id === endpointId);
54
+ if (!endpoint) throw new Error(`background session delivery endpoint not found: ${endpointId}`);
55
+ const credentials = resolveFeishuEndpointCredentials(endpoint.credentialRef, context.env);
56
+ const config = {
57
+ agentId: endpoint.agentId,
58
+ feishu: {
59
+ ...credentials,
60
+ baseUrl: endpoint.baseUrl,
61
+ cardStreamLeaseMs: endpoint.cardStreamLeaseMs,
62
+ streamMinIntervalMs: endpoint.streamMinIntervalMs
63
+ },
64
+ pi: {}
65
+ };
66
+ const sender = createConfiguredFeishuBackgroundSessionDelivery({
67
+ client: createOpenApiClient(config),
68
+ config
69
+ });
70
+ deliveryClients.set(endpointId, sender);
71
+ return sender;
72
+ };
73
+ const supervisor = createBackgroundSessionSupervisor({
74
+ clock: { now: () => (/* @__PURE__ */ new Date()).toISOString() },
75
+ config: {
76
+ intervalMs: resolveBackgroundSessionSupervisorIntervalMs(input.config.leaseMs),
77
+ leaseMs: input.config.leaseMs,
78
+ leaseRenewalIntervalMs: input.config.leaseRenewalIntervalMs,
79
+ maxConcurrentSessions: input.config.maxConcurrentSessions,
80
+ maxConsecutiveFailures: input.config.maxConsecutiveFailures,
81
+ retryBackoffMs: input.config.retryBackoffMs,
82
+ sessionLifetimeMs: input.config.sessionLifetimeMs
83
+ },
84
+ deliveries: sessionDeliveries,
85
+ deliver: async (delivery) => {
86
+ const session = await sessionRepository.get(delivery.sessionId);
87
+ if (!session) throw new Error(`background session not found for delivery: ${delivery.sessionId}`);
88
+ if (!session.origin.conversationId) throw new Error(`background session has no delivery conversation: ${delivery.sessionId}`);
89
+ return (await resolveDeliverySender(session.origin.endpointId)).deliver({
90
+ chatId: resolveFeishuDeliveryChatId(session.origin.conversationId),
91
+ deliveryId: delivery.deliveryId,
92
+ displayName: session.displayName,
93
+ kind: delivery.kind,
94
+ sessionId: session.sessionId,
95
+ text: delivery.text
96
+ });
97
+ },
98
+ onError: (error) => {
99
+ console.error("Background session supervisor failed", error);
100
+ },
101
+ repository: sessionRepository,
102
+ runStep: async ({ session, signal, wakeText }) => {
103
+ let runId;
104
+ const invocation = {
105
+ allowedActorOpenIds: session.origin.allowedActorOpenIds,
106
+ ...session.origin.conversationId ? { conversationId: session.origin.conversationId } : {},
107
+ endpointId: session.origin.endpointId,
108
+ kind: "background-session",
109
+ ...session.origin.memory ? { memory: session.origin.memory } : {},
110
+ sessionId: session.sessionId,
111
+ sourceMessageId: createBackgroundSessionStepSourceMessageId(session.sessionId, session.stepCount + 1),
112
+ tenantKey: session.origin.tenantKey
113
+ };
114
+ const abortPromise = new Promise((_resolve, reject) => {
115
+ signal.addEventListener("abort", () => {
116
+ if (runId) input.cancel({
117
+ agentId: session.authority.agentId,
118
+ reason: "background session step aborted",
119
+ runId,
120
+ sessionKey: session.authority.sessionKey
121
+ });
122
+ reject(/* @__PURE__ */ new Error("background session step aborted"));
123
+ }, { once: true });
124
+ });
125
+ const runPromise = input.run({
126
+ agentId: session.authority.agentId,
127
+ invocation,
128
+ onUpdate: (update) => {
129
+ if (update.event.type === "agent_run_accepted" && !runId) runId = update.event.runId;
130
+ },
131
+ sessionKey: session.authority.sessionKey,
132
+ text: wakeText
133
+ }).then((result) => readStepRunResult(result));
134
+ return Promise.race([runPromise, abortPromise]);
135
+ },
136
+ sleep
137
+ });
138
+ let running = false;
139
+ return {
140
+ running: () => running,
141
+ status: () => supervisor.status(),
142
+ start: async () => {
143
+ await Effect.runPromise(supervisor.recover());
144
+ await Effect.runPromise(supervisor.start());
145
+ running = true;
146
+ },
147
+ stop: async () => {
148
+ await Effect.runPromise(supervisor.stop());
149
+ running = false;
150
+ }
151
+ };
152
+ };
153
+ return {
154
+ dispose: () => telemetry?.shutdown(),
155
+ createRecoveryControl: () => openJsonlRecoveryControl({
156
+ endpointsDirectory: join(STATE_DIR, "endpoints"),
157
+ instancesDirectory: join(STATE_DIR, "instances")
158
+ }),
159
+ createBackgroundSession: backgroundSessionsConfig?.enabled ? (input) => createBackgroundSessionAdapter(input) : void 0,
160
+ createAutomation: async (input) => {
161
+ const credentials = resolveFeishuEndpointCredentials(input.deliveryEndpoint.credentialRef, context.env);
162
+ const config = {
163
+ agentId: input.definition.agentId,
164
+ feishu: {
165
+ ...credentials,
166
+ baseUrl: input.deliveryEndpoint.baseUrl,
167
+ cardStreamLeaseMs: input.deliveryEndpoint.cardStreamLeaseMs,
168
+ streamMinIntervalMs: input.deliveryEndpoint.streamMinIntervalMs
169
+ },
170
+ pi: {}
171
+ };
172
+ const sender = createConfiguredFeishuAutomationCardSender({
173
+ client: createOpenApiClient(config),
174
+ config
175
+ });
176
+ const repository = await openJsonAutomationTickRepository({ filePath: join(STATE_DIR, "automations", createHash("sha256").update(input.automationId).digest("hex").slice(0, 16), "ticks.json") });
177
+ const target = resolveAutomationTarget(input.definition.delivery.targetRef, context.env);
178
+ return createScheduledAutomation({
179
+ automationId: input.automationId,
180
+ binding: {
181
+ agentId: input.definition.agentId,
182
+ bindingId: input.automationId,
183
+ delivery: {
184
+ endpointId: input.definition.delivery.endpointId,
185
+ targetKey: createHash("sha256").update(target).digest("hex"),
186
+ targetType: input.definition.delivery.targetType
187
+ },
188
+ schedule: input.definition.schedule,
189
+ servicePrincipalId: `automation:${input.automationId}`,
190
+ skillGrantRevision: input.definition.runtimeDefinition.skillGrantSet.revision,
191
+ skillIds: input.definition.template.requestedSkillIds,
192
+ templateId: input.definition.templateId,
193
+ timeZone: input.definition.timeZone,
194
+ toolIds: input.definition.template.requestedToolIds
195
+ },
196
+ createInput: input.definition.template.createInput,
197
+ deliver: ({ body, idempotencyKey, presentation }) => Effect.runPromise(sender.send({
198
+ idempotencyKey,
199
+ receiveId: target,
200
+ receiveIdType: input.definition.delivery.targetType,
201
+ markdown: body,
202
+ ...presentation === void 0 ? {} : { presentation }
203
+ })),
204
+ onError: () => {
205
+ console.error(`Scheduled Automation ${input.automationId} failed; it will retry`);
206
+ },
207
+ repository,
208
+ run: async (runInput) => {
209
+ const result = readAutomationRunResult(await input.run(runInput));
210
+ const projected = result.body === void 0 ? void 0 : input.definition.template.createPresentation?.({
211
+ occurrence: runInput.occurrence,
212
+ text: result.body
213
+ });
214
+ const presentation = projected ? readAutomationPresentation(projected) : void 0;
215
+ return {
216
+ ...result,
217
+ ...presentation === void 0 ? {} : { presentation }
218
+ };
219
+ }
220
+ });
221
+ },
222
+ createEndpoint: async (input) => {
223
+ const credentials = resolveFeishuEndpointCredentials(input.definition.credentialRef, context.env);
224
+ const botOpenId = await resolveFeishuBotOpenId(credentials, input.definition.baseUrl);
225
+ const endpointState = join(STATE_DIR, "endpoints", input.endpointId);
226
+ const cardTargets = createJsonFileFeishuCardTargetRegistry({ filePath: join(endpointState, "feishu-card-targets.json") });
227
+ const cardLedger = await openJsonlFeishuCardDeliveryLedger({ filePath: join(endpointState, "feishu-card-delivery.jsonl") });
228
+ const inbox = await openJsonlFeishuInboxRepository({ filePath: join(endpointState, "feishu-inbox.jsonl") });
229
+ const sessionStore = await openJsonFeishuSessionStore({ filePath: join(endpointState, "feishu-session-store.json") });
230
+ const config = {
231
+ agentId: input.agentId,
232
+ feishu: {
233
+ ...credentials,
234
+ baseUrl: input.definition.baseUrl,
235
+ cardStreamLeaseMs: input.definition.cardStreamLeaseMs,
236
+ streamMinIntervalMs: input.definition.streamMinIntervalMs
237
+ },
238
+ pi: {}
239
+ };
240
+ const openApiClient = createOpenApiClient(config);
241
+ const promptContext = createFeishuTopicContextResolver({
242
+ baseUrl: input.definition.baseUrl,
243
+ client: openApiClient
244
+ });
245
+ const cotPublisher = input.definition.experimental?.cotMessages ? createFeishuCotPublisher({
246
+ baseUrl: resolveExperimentalCotBaseUrl(context.env),
247
+ client: openApiClient,
248
+ minIntervalMs: input.definition.streamMinIntervalMs
249
+ }) : void 0;
250
+ const interactions = createHumanInteractionService({
251
+ clock: { now: () => (/* @__PURE__ */ new Date()).toISOString() },
252
+ presenter: createConfiguredFeishuHumanInteractionPresenter({
253
+ client: openApiClient,
254
+ config
255
+ }),
256
+ repository: createJsonlHumanInteractionRepository({ filePath: join(endpointState, "human-interactions.jsonl") })
257
+ });
258
+ const cardRollover = createConfiguredFeishuCardRolloverRuntime({
259
+ agentName: input.agentId,
260
+ cardTargets,
261
+ client: openApiClient,
262
+ clock: createSystemClock(),
263
+ config,
264
+ ledger: cardLedger,
265
+ onError: (error) => {
266
+ console.error(`Feishu card rollover failed for endpoint ${input.endpointId}`, error);
267
+ },
268
+ ...input.definition.progressDisplay === void 0 ? {} : { progressDisplay: input.definition.progressDisplay },
269
+ sleep,
270
+ title: input.agentId
271
+ });
272
+ const publisher = cardRollover.rollover;
273
+ const endpointEvents = createJsonlAgentEventLog({ filePath: join(STATE_DIR, "instances", input.instanceId, "agent-events.jsonl") });
274
+ const endpointInitialEvents = await Effect.runPromise(endpointEvents.readAll());
275
+ await Effect.runPromise(createFeishuCardDeliveryReconciler({
276
+ events: endpointInitialEvents,
277
+ ledger: cardLedger,
278
+ publish: (action) => publisher.publish(action)
279
+ }).reconcile());
280
+ const replies = createConfiguredFeishuTextReplySender({
281
+ client: openApiClient,
282
+ config
283
+ });
284
+ const prepareCardTarget = (run) => cardRollover.prepareRun(run);
285
+ const endpoint = createFeishuDeploymentEndpoint({
286
+ agentId: input.agentId,
287
+ botOpenId,
288
+ cardRollover: cardRollover.transport,
289
+ finalizeRun: (runId) => cardRollover.rollover.releaseRun(runId),
290
+ cancel: input.cancel,
291
+ endpointId: input.endpointId,
292
+ eventDispatcher: createLazyFeishuWebSocketEventDispatcher(() => new Lark.EventDispatcher({})),
293
+ groupPolicy: input.definition.groupPolicy,
294
+ handle: input.handle,
295
+ inboxRepository: inbox,
296
+ initialEvents: endpointInitialEvents,
297
+ interactions,
298
+ maxPendingMessages: 100,
299
+ memoryTenantId,
300
+ ...input.projectSpaceId ? { projectSpaceId: input.projectSpaceId } : {},
301
+ onCapacityExceeded: (payload) => replies.reply(payload.event.message.message_id, "Rivus is busy. Please retry in a moment."),
302
+ prepareRun: createFeishuPresentationPreparation({
303
+ ...cotPublisher ? { cotPublisher } : {},
304
+ prepareCardTarget,
305
+ reportCotError: (operation, error) => reportCotError(input.endpointId, operation, error)
306
+ }),
307
+ promptContext,
308
+ publish: (action) => publisher.publish(action),
309
+ reply: (messageId, text) => replies.reply(messageId, text),
310
+ sessionStore,
311
+ ...input.steer ? { steer: input.steer } : {},
312
+ ...cotPublisher ? { publishRunUpdate: (update) => cotPublisher.publish(update).pipe(Effect.catchAll((error) => reportCotError(input.endpointId, "update", error))) } : {},
313
+ sessionNamespace: input.definition.sessionNamespace,
314
+ sleep,
315
+ websocketClient: createLazyFeishuWebSocketClient(credentials, input.definition.baseUrl),
316
+ workerConcurrency: 4
317
+ });
318
+ interactionRegistry.register(input.endpointId, interactions);
319
+ return endpoint;
320
+ },
321
+ createRuntime: async (input) => {
322
+ const instanceState = join(STATE_DIR, "instances", input.instanceId);
323
+ await mkdir(instanceState, { recursive: true });
324
+ const eventLog = createJsonlAgentEventLog({ filePath: join(instanceState, "agent-events.jsonl") });
325
+ const initialEvents = await Effect.runPromise(eventLog.readAll());
326
+ const broker = createToolBroker({
327
+ approvals: createRoutedHumanInteractionToolApprovalService(interactionRegistry),
328
+ catalog: input.catalog,
329
+ hostTools: [...input.definition.memory.tool ? [createRivusMemoryToolDescriptor({ memory })] : [], ...backgroundService ? [...createBackgroundSessionHostTools({
330
+ createSessionId: () => `bg-${randomUUID()}`,
331
+ definition: input.definition,
332
+ service: backgroundService
333
+ })] : []],
334
+ operations: await openJsonlToolOperationLedger({ filePath: join(instanceState, "tool-operations.jsonl") }),
335
+ policy: { current: async () => ({
336
+ epoch: 1,
337
+ revokedToolIds: []
338
+ }) }
339
+ });
340
+ const resolveToolName = createPiToolNameResolver(input.definition.tools);
341
+ const skillRuntime = createPiSkillRuntime(input.definition.skills);
342
+ const workingDirectory = input.projectSpace?.workingDirectory ?? process.cwd();
343
+ const workspaceRoot = input.projectSpace?.root ?? process.cwd();
344
+ const workspaceInstructions = await createAgentsMdInstructionsProvider().resolve({
345
+ maxBytes: 64 * 1024,
346
+ workingDirectory: relative(workspaceRoot, workingDirectory) || ".",
347
+ workspaceRoot: await createWorkspaceRootHandle(workspaceRoot)
348
+ });
349
+ const prepareProjectMemory = input.projectSpace && input.definition.memory.scopes.includes("project") ? createProjectMemoryPromptPreparer({
350
+ agentId: input.agentId,
351
+ memory,
352
+ projectId: input.projectSpace.id
353
+ }) : void 0;
354
+ const sessionRegistry = createPiSessionRegistry({ createSession: async (firstInput) => {
355
+ let activeInput = firstInput;
356
+ const resources = await createPiSessionResources({
357
+ agentDir: PI_AGENT_DIR,
358
+ appendSystemPromptOverride: () => [workspaceInstructions.content, skillRuntime.prompt].filter((content) => content.length > 0),
359
+ cwd: workingDirectory,
360
+ homeDirectory: homedir(),
361
+ ...input.projectSpace ? { projectSkillPaths: input.projectSpace.skillPaths } : {},
362
+ systemPromptOverride: () => input.definition.systemPrompt
363
+ });
364
+ const customTools = [
365
+ ...createPiSkillReadTools({
366
+ cwd: workingDirectory,
367
+ runtimeToolIds: input.definition.runtimeToolGrantSet.toolIds,
368
+ skillPaths: resources.skillNames.size > 0 ? resources.skillPaths : []
369
+ }),
370
+ ...createPiToolProxyDefinitions({
371
+ agentId: input.agentId,
372
+ approvals: createHumanInteractionToolApprovalGateway({ registry: interactionRegistry }),
373
+ broker,
374
+ getActiveInput: () => activeInput,
375
+ instanceId: input.instanceId,
376
+ memoryScopes: input.definition.memory.scopes,
377
+ toolGrantSet: input.definition.toolGrantSet,
378
+ tools: input.definition.tools
379
+ }),
380
+ ...skillRuntime.tool ? [skillRuntime.tool] : []
381
+ ];
382
+ const activeToolNames = resolvePiSessionToolNames(input.definition.runtimeToolGrantSet.toolIds, customTools);
383
+ const result = await createAgentSession(resources.withSessionOptions({
384
+ ...piOptions,
385
+ customTools,
386
+ excludeTools: [],
387
+ sessionManager: SessionManager.create(workingDirectory, join(instanceState, "sessions")),
388
+ tools: [...activeToolNames]
389
+ }));
390
+ return {
391
+ activate: (loopInput) => {
392
+ activeInput = loopInput;
393
+ },
394
+ dispose: () => result.session.dispose(),
395
+ preparePrompt: async (loopInput) => {
396
+ validatePiSkillCommand(loopInput.text, resources.skillNames);
397
+ return prepareProjectMemory ? prepareProjectMemory(loopInput) : loopInput.text;
398
+ },
399
+ resolveToolName,
400
+ session: result.session
401
+ };
402
+ } });
403
+ const loop = createPiAgentLoop({
404
+ disposeSessionAfterRun: false,
405
+ ...telemetry ? { modelContentObserver: telemetry.modelContentObserver } : {},
406
+ resolveSession: (loopInput) => sessionRegistry.resolve(loopInput)
407
+ });
408
+ const scheduler = createSessionScheduler({
409
+ createRuntime: (sessionKey) => createAgentHarnessPooledRuntime(createAgentHarness({
410
+ clock: createSystemClock(),
411
+ eventSinks: telemetry ? [eventLog, telemetry.sink] : [eventLog],
412
+ initialEvents: eventsForSession(initialEvents, sessionKey),
413
+ loop,
414
+ runIds: createUuidRunIds(),
415
+ ...input.binding.kind === "background-session" && backgroundSessionsConfig ? { runTimeoutMs: backgroundSessionsConfig.stepTimeoutMs } : {}
416
+ })),
417
+ maxConcurrentSessions: input.binding.kind === "background-session" ? backgroundSessionsConfig?.maxConcurrentSessions ?? 4 : 4,
418
+ maxQueuedRuns: 32
419
+ });
420
+ return {
421
+ ...scheduler,
422
+ dispose: async () => {
423
+ await scheduler.dispose?.();
424
+ await sessionRegistry.disposeAll();
425
+ }
426
+ };
427
+ }
428
+ };
429
+ }
430
+ function eventsForSession(events, sessionKey) {
431
+ const runIds = new Set(events.filter((event) => event.sessionKey === sessionKey).map((event) => event.runId));
432
+ return events.filter((event) => runIds.has(event.runId));
433
+ }
434
+ function resolveAutomationTarget(targetRef, env) {
435
+ if (!targetRef.startsWith("env:")) throw new Error("Automation delivery targetRef must use env:<VARIABLE>");
436
+ const variable = targetRef.slice(4);
437
+ if (!/^[A-Z][A-Z0-9_]*$/.test(variable)) throw new Error(`Invalid Automation delivery targetRef: ${targetRef}`);
438
+ const target = env[variable]?.trim();
439
+ if (!target) throw new Error(`${variable} is required`);
440
+ return target;
441
+ }
442
+ function resolveExperimentalCotBaseUrl(env) {
443
+ const baseUrl = env.RIVUS_FEISHU_COT_BASE_URL?.trim();
444
+ if (!baseUrl) throw new Error("RIVUS_FEISHU_COT_BASE_URL is required when experimental.cotMessages is enabled");
445
+ return baseUrl;
446
+ }
447
+ function reportCotError(endpointId, operation, error) {
448
+ return Effect.sync(() => {
449
+ const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
450
+ console.error(`Experimental Feishu COT ${operation} failed for endpoint ${endpointId}: ${detail}`);
451
+ });
452
+ }
453
+ function readAutomationRunResult(result) {
454
+ const { finalText, runId } = readStepRunResult(result);
455
+ const trimmedText = finalText.trim();
456
+ if (trimmedText.startsWith("RIVUS_AUTOMATION_SUPPRESSED:")) {
457
+ const reason = trimmedText.slice(AUTOMATION_SUPPRESSION_PREFIX.length).trim();
458
+ if (!reason) throw new Error("Scheduled Automation suppression requires a reason");
459
+ return {
460
+ runId,
461
+ suppressedReason: reason
462
+ };
463
+ }
464
+ if (!trimmedText) throw new Error("Scheduled Automation Agent Run did not produce final text");
465
+ return {
466
+ body: finalText,
467
+ runId
468
+ };
469
+ }
470
+ function readStepRunResult(result) {
471
+ if (result !== null && typeof result === "object" && "finalText" in result && typeof result.finalText === "string" && "runId" in result && typeof result.runId === "string" && result.runId.trim() !== "") return {
472
+ finalText: result.finalText,
473
+ runId: result.runId
474
+ };
475
+ throw new Error("Background session Agent Run did not produce a runId and final text");
476
+ }
477
+ function createLazyFeishuWebSocketClient(credentials, domain) {
478
+ let client;
479
+ let connected = false;
480
+ return {
481
+ connected: () => connected,
482
+ close: () => {
483
+ client?.close();
484
+ client = void 0;
485
+ connected = false;
486
+ },
487
+ start: (options) => new Promise((resolve, reject) => {
488
+ let settled = false;
489
+ const settle = (callback) => {
490
+ if (settled) return;
491
+ settled = true;
492
+ clearTimeout(timeout);
493
+ callback();
494
+ };
495
+ const timeout = setTimeout(() => settle(() => reject(/* @__PURE__ */ new Error("Feishu WebSocket handshake timed out after 15000ms"))), 15e3);
496
+ client ??= new Lark.WSClient({
497
+ ...credentials,
498
+ domain,
499
+ handshakeTimeoutMs: 1e4,
500
+ onError: (error) => {
501
+ connected = false;
502
+ settle(() => reject(error));
503
+ },
504
+ onReady: () => {
505
+ connected = true;
506
+ settle(resolve);
507
+ },
508
+ onReconnected: () => {
509
+ connected = true;
510
+ },
511
+ onReconnecting: () => {
512
+ connected = false;
513
+ }
514
+ });
515
+ client.start(options).catch((error) => {
516
+ connected = false;
517
+ settle(() => reject(error));
518
+ });
519
+ })
520
+ };
521
+ }
522
+ async function resolveFeishuBotOpenId(credentials, domain) {
523
+ const response = await new Lark.Client({
524
+ ...credentials,
525
+ domain
526
+ }).request({
527
+ method: "GET",
528
+ url: "/open-apis/bot/v3/info"
529
+ });
530
+ const openId = response.bot?.open_id;
531
+ if (response.code !== 0 || !openId) throw new Error(`Feishu bot identity lookup failed: ${response.msg ?? "response missing bot.open_id"}`);
532
+ return openId;
533
+ }
534
+ async function createPiSessionOptions(context) {
535
+ const authStorage = AuthStorage.create(PI_AUTH_FILE);
536
+ const modelReference = optional(context.env.PI_MODEL);
537
+ const configuredModel = modelReference ? parseModelReference(modelReference) : void 0;
538
+ const provider = configuredModel?.provider;
539
+ const apiKey = await resolvePiApiKey(context.env);
540
+ const baseUrl = optional(context.env.PI_BASE_URL);
541
+ if ((apiKey || baseUrl) && !provider) throw new Error("PI_API_KEY and PI_BASE_URL require PI_MODEL in provider/model form");
542
+ if (apiKey) authStorage.setRuntimeApiKey(provider, apiKey);
543
+ if (baseUrl) await writeProviderBaseUrlOverride(provider, baseUrl);
544
+ const modelRegistry = ModelRegistry.create(authStorage, baseUrl ? PI_MODELS_FILE : void 0);
545
+ const model = configuredModel ? modelRegistry.find(configuredModel.provider, configuredModel.modelId) : void 0;
546
+ if (modelReference && !model) throw new Error(`PI_MODEL ${modelReference} was not found in the Pi model registry`);
547
+ const thinkingLevel = readThinkingLevel(context.env.PI_THINKING_LEVEL);
548
+ return {
549
+ authStorage,
550
+ cwd: process.cwd(),
551
+ modelRegistry,
552
+ ...model ? { model } : {},
553
+ ...thinkingLevel ? { thinkingLevel } : {}
554
+ };
555
+ }
556
+ async function resolvePiApiKey(env) {
557
+ const inline = optional(env.PI_API_KEY);
558
+ const filePath = optional(env.PI_API_KEY_FILE);
559
+ if (inline && filePath) throw new Error("PI_API_KEY and PI_API_KEY_FILE cannot both be set");
560
+ if (inline) return inline;
561
+ if (!filePath) return void 0;
562
+ const contents = optional(await readFile(filePath, "utf8"));
563
+ if (!contents) throw new Error("PI_API_KEY_FILE must not be empty");
564
+ return contents;
565
+ }
566
+ function optional(value) {
567
+ return value?.trim() || void 0;
568
+ }
569
+ function parseModelReference(reference) {
570
+ const separator = reference.indexOf("/");
571
+ if (separator <= 0 || separator === reference.length - 1) throw new Error("PI_MODEL must use provider/model form, for example zai/glm-5.1");
572
+ return {
573
+ modelId: reference.slice(separator + 1),
574
+ provider: reference.slice(0, separator)
575
+ };
576
+ }
577
+ function readThinkingLevel(value) {
578
+ const level = optional(value);
579
+ if (!level) return void 0;
580
+ if (!THINKING_LEVELS.has(level)) throw new Error("PI_THINKING_LEVEL must be one of off, minimal, low, medium, high, xhigh");
581
+ return level;
582
+ }
583
+ function sleep(ms) {
584
+ return Effect.promise(() => new Promise((resolve) => setTimeout(resolve, ms)));
585
+ }
586
+ async function writeProviderBaseUrlOverride(provider, baseUrl) {
587
+ await mergePiProviderBaseUrlOverride({
588
+ baseUrl,
589
+ filePath: PI_MODELS_FILE,
590
+ provider
591
+ });
592
+ }
593
+ //#endregion
594
+ export { createRivusDeploymentAdapters };