Skip to content

Support bootstrapping sessions from external chat transcripts #91

Description

@rama-adi

Summary

I’d like eve to support bootstrapping a client/session from an existing external chat transcript that was not originally created by an eve durable execution.

This would help teams that want to migrate existing conversations into eve, or teams that want to own chat persistence themselves while still using eve for new agent turns.

This is related to #75, but distinct: #75 is about rewinding/forking an existing eve durable session. This request is about starting from transcript history when there is no existing eve sessionId, continuationToken, stream cursor, event log, sandbox state, or workflow instance.

Use case

Two common cases:

  1. Migrating to eve: an app already has stored chat transcripts from another system and wants users to continue those conversations through eve.
  2. App-owned chat persistence: the app persists normalized chat history in its own database and wants to hydrate eve/client state from that history, rather than treating eve’s durable session event stream as the only source of chat history.

In both cases, the app has prior user/assistant/toolCall/thinking messages but no eve-native session handles.

The desired flow is something like:

  1. Frontend loads an app-owned conversation and displays its transcript.
  2. Frontend sends a DB-backed conversation ID with the first eve request.
  3. The eve server resolves that ID to the stored transcript before the model turn starts.
  4. Eve starts the new turn with that transcript as prior conversation history.
  5. From that point forward, the new eve turn can be backed by a normal durable eve execution instance.

I’m flexible on the exact mechanism. Client-provided initial history, a server-side start-of-turn hook, a channel hook that resolves transcript history from a DB ID, or another API shape that fits eve’s DX would all work for my use case. The important capability is being able to attach an old transcript as real prior conversation history.

Current behavior

I looked at the latest main branch and, from a quick code/docs pass:

  • ClientSession.state is the public dehydration surface for live eve sessions. It stores only sessionId, continuationToken, and streamIndex. See packages/eve/src/client/types.ts and docs/guides/client/continuations.mdx.

  • client.session(savedState) can rehydrate that cursor, but only when the durable eve session already exists.

  • The stream API can replay events by sessionId and startIndex, which is enough to reconstruct a UI from an eve event stream, but not from an external transcript that never had an eve sessionId.

  • Internally, durable sessions do persist model history as history: ModelMessage[]. See packages/eve/src/execution/durable-session-store.ts.

  • createSession() currently initializes history: [], and I did not find a public HTTP/client API that accepts initial history or imports a transcript.

So the gap seems to be external/app-owned transcript bootstrapping, not ordinary session resume.

Current workaround

This can be somewhat shoehorned today by adding the transcript as channel context when the session starts. For example, the frontend could send an app-owned conversation ID, and the eve channel could fetch the transcript:

export default eveChannel({
  async onMessage(ctx, message) {
    const conversationId = new URL(ctx.eve.request.url).searchParams.get(
      "conversationId",
    );

    const transcript = conversationId
      ? await loadTranscriptFromYourDb(conversationId)
      : [];

    return {
      auth: defaultEveAuth(ctx),
      context: [
        formatTranscriptAsContext(transcript),
      ],
    };
  },
});

This works only as textual context because context is typed as string[], not ModelMessage[]. Each context string lands in durable session.history as a user-role message before the actual user message, roughly like:

[
  { role: "user", content: "Prior external transcript:\n..." },
  { role: "user", content: "Continue from where we left off." },
  { role: "assistant", content: "...new eve response..." },
]

That is useful, but it is not equivalent to first-class transcript bootstrapping. The imported transcript becomes context about a prior conversation, not actual alternating prior user/assistant history. It also does not give clients a first-class way to hydrate UI messages from app-owned history.

Possible API shape

Any of these would work from my perspective:

  • Client-provided initial history: the client sends initial messages directly with the first request.
  • Server-resolved initial history: a channel hook or start-of-turn hook resolves initial history from a DB-backed ID before session history is constructed.
  • Another eve-native shape: whatever the maintainers think best fits eve’s durability/session/channel model.

For example, client-side:

await session.send({
  message: "Continue from where we left off.",
  initialHistory: transcript,
});

Or server-side:

export default eveChannel({
  async initialHistory(ctx) {
    const conversationId = getConversationId(ctx.eve.request);
    return await loadTranscriptFromYourDb(conversationId);
  },
});

The exact API does not need to be either of these. The important part is that apps can attach old transcript messages before the first eve turn starts.

Design questions

  • Is there already a start-of-turn hook that could support this cleanly?
  • Should initial history be provided by the client, resolved server-side, or both?
  • Should eve accept AI SDK ModelMessage[], eve stream events, or a narrower transcript format?
  • Should imported transcript history become true durable session history once the first eve turn starts?
  • Should there be a UI-only hydration API separate from model-history seeding?
  • How should tool calls/tool results be validated so imported history is provider-safe?
  • How should imported history interact with compaction?
  • Should this be limited to text-only user/assistant history at first?
  • What should happen to channel state, auth, sandbox state, and continuation lineage, given that external/app-owned transcripts do not have those eve-native pieces?

Why this matters

A supported transcript bootstrap/import primitive would make eve easier to adopt for apps with existing conversations and for apps that intentionally keep chat persistence in their own database.


Disclosure: I used Codex to help inspect the current code/docs and draft this issue, but I have read and reviewed the final text.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions