@fastagent-sh/fastagent 0.22.0 → 0.22.1
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/dist/engines/pi/invoke-session.js +24 -0
- package/dist/session.d.ts +13 -1
- package/package.json +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { contentText } from "@earendil-works/pi-ai";
|
|
1
2
|
import * as Deferred from "effect/Deferred";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
3
4
|
import * as Fiber from "effect/Fiber";
|
|
@@ -91,6 +92,28 @@ function trackExtensionTurns(session) {
|
|
|
91
92
|
session.sendCustomMessage = (...args) => track(sendCustomMessage(...args));
|
|
92
93
|
return pending;
|
|
93
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Report each user message when it is WRITTEN, which is later than pi announces it: pi awaits extension `message_end`
|
|
97
|
+
* handlers before it appends. Emitting from the write is what makes `user_message.entryId` readable through
|
|
98
|
+
* `entries()` by the time the event arrives, so a reconnecting client's backfill cannot miss a message whose event
|
|
99
|
+
* fired before it subscribed. pi's agent awaits each listener before the next event, so the message still reports
|
|
100
|
+
* before the answer to it. The in-memory store reuses one record across runs, so the release restores the method.
|
|
101
|
+
*/
|
|
102
|
+
function reportUserMessages(session, report) {
|
|
103
|
+
const record = session.sessionManager;
|
|
104
|
+
const append = record.appendMessage;
|
|
105
|
+
return Effect.acquireRelease(Effect.sync(() => {
|
|
106
|
+
record.appendMessage = (message) => {
|
|
107
|
+
const entryId = append.call(record, message);
|
|
108
|
+
// The same text `entries()` publishes for this entry (session-control.ts toSessionEntry).
|
|
109
|
+
if (message.role === "user")
|
|
110
|
+
report(entryId, contentText(message.content, ""));
|
|
111
|
+
return entryId;
|
|
112
|
+
};
|
|
113
|
+
}), () => Effect.sync(() => {
|
|
114
|
+
record.appendMessage = append;
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
94
117
|
export function createPiAgentFromSession(options) {
|
|
95
118
|
const { sessionFactory, lease = inProcessLease(), observer } = options;
|
|
96
119
|
async function* turn(scope, prompt, { onCancelReady, wasCancelled }) {
|
|
@@ -217,6 +240,7 @@ export function createPiAgentFromSession(options) {
|
|
|
217
240
|
if (OWED_BY_THE_RUN.has(error.event))
|
|
218
241
|
extensionFailure ??= `${error.event} failed (${error.extensionPath}): ${error.error}`;
|
|
219
242
|
})), (unsubscribe) => Effect.sync(unsubscribe));
|
|
243
|
+
yield* reportUserMessages(session, (entryId, text) => observe({ type: "user_message", timestamp: Date.now(), runId, data: { entryId, text } }));
|
|
220
244
|
const extensionTurns = trackExtensionTurns(session);
|
|
221
245
|
// Completing the gate can run waiting controls synchronously; their queue events must be observed.
|
|
222
246
|
yield* Deferred.succeed(bound, session);
|
package/dist/session.d.ts
CHANGED
|
@@ -280,6 +280,18 @@ export type RunSettledEvent = SessionEvent<"run_settled", {
|
|
|
280
280
|
export type MessageStartedEvent = SessionEvent<"message_started", Record<never, never>> & {
|
|
281
281
|
runId: string;
|
|
282
282
|
};
|
|
283
|
+
/**
|
|
284
|
+
* A user message entered the conversation: the run's opening prompt, a steer or follow-up leaving `pending`, or one an
|
|
285
|
+
* extension sent. It reports after the message is recorded, so `entries()` already holds `entryId` with the same
|
|
286
|
+
* `text` (a slash command expanded, images not included), and before the answer to it starts. The one live event a
|
|
287
|
+
* backfill can be deduplicated against exactly.
|
|
288
|
+
*/
|
|
289
|
+
export type UserMessageEvent = SessionEvent<"user_message", {
|
|
290
|
+
entryId: string;
|
|
291
|
+
text: string;
|
|
292
|
+
}> & {
|
|
293
|
+
runId: string;
|
|
294
|
+
};
|
|
283
295
|
export type MessageDeltaEvent = SessionEvent<"message_delta", {
|
|
284
296
|
channel: "text" | "thinking";
|
|
285
297
|
delta: string;
|
|
@@ -368,4 +380,4 @@ export type ServingErrorEvent = SessionEvent<"serving_error", {
|
|
|
368
380
|
* Every event the in-process observation plane emits today: L0, L1 `queue_changed`, and the L2 events
|
|
369
381
|
* (`state_changed`, `compaction_*`, `retry_scheduled`).
|
|
370
382
|
*/
|
|
371
|
-
export type KnownSessionEvent = RunStartedEvent | RunSettledEvent | MessageStartedEvent | MessageDeltaEvent | MessageFinishedEvent | ToolStartedEvent | ToolProgressEvent | ToolFinishedEvent | QueueChangedEvent | StateChangedEvent | CompactionStartedEvent | CompactionFinishedEvent | RetryScheduledEvent;
|
|
383
|
+
export type KnownSessionEvent = RunStartedEvent | RunSettledEvent | MessageStartedEvent | UserMessageEvent | MessageDeltaEvent | MessageFinishedEvent | ToolStartedEvent | ToolProgressEvent | ToolFinishedEvent | QueueChangedEvent | StateChangedEvent | CompactionStartedEvent | CompactionFinishedEvent | RetryScheduledEvent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastagent-sh/fastagent",
|
|
3
|
-
"version": "0.22.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on Telegram, Slack, Feishu, or behind any channel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|