@cognition-ai/cloudflare-agents 0.0.1-beta.3 → 0.0.1-beta.5
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/devin-chat-agent.js
CHANGED
|
@@ -230,7 +230,6 @@ let DevinChatAgent = (() => {
|
|
|
230
230
|
writer.merge(toUIMessageStream(turn.events(prompt, toolCallIds(this.messages)), {
|
|
231
231
|
approvals: turn.approvals,
|
|
232
232
|
messageMetadata: devinSessionMetadata(session),
|
|
233
|
-
onError: errorText,
|
|
234
233
|
onEvent: (event) => {
|
|
235
234
|
this.#project(epoch, session, event);
|
|
236
235
|
},
|
|
@@ -340,14 +339,11 @@ class Turn {
|
|
|
340
339
|
async *events(prompt, earlierToolCalls) {
|
|
341
340
|
this.#started = true;
|
|
342
341
|
const turn = this.#session.stream(prompt, { signal: this.#stop.signal });
|
|
343
|
-
let finished = false;
|
|
344
342
|
try {
|
|
345
343
|
for (;;) {
|
|
346
344
|
const next = await turn.next();
|
|
347
|
-
if (next.done)
|
|
348
|
-
finished = true;
|
|
345
|
+
if (next.done)
|
|
349
346
|
return next.value;
|
|
350
|
-
}
|
|
351
347
|
const event = next.value;
|
|
352
348
|
if (event.type === "tool_call" && earlierToolCalls.has(event.call.id))
|
|
353
349
|
continue;
|
|
@@ -355,9 +351,8 @@ class Turn {
|
|
|
355
351
|
}
|
|
356
352
|
}
|
|
357
353
|
finally {
|
|
358
|
-
//
|
|
359
|
-
|
|
360
|
-
await turn.return(undefined);
|
|
354
|
+
// If the consumer stopped early, let the SDK's generator run its cleanup too.
|
|
355
|
+
await turn.return(undefined);
|
|
361
356
|
this.#close();
|
|
362
357
|
}
|
|
363
358
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"devin-chat-agent.js","sourceRoot":"","sources":["../src/devin-chat-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AIChatAgent,\n type ChatRecoveryContext,\n type ChatRecoveryOptions,\n type OnChatMessageOptions,\n} from \"@cloudflare/ai-chat\";\nimport {\n devinSessionMetadata,\n toPromptInput,\n toUIMessages,\n toUIMessageStream,\n ToolApprovals,\n type DevinMessageMetadata,\n type DevinUIMessage,\n} from \"@cognition-ai/ai-sdk\";\nimport {\n DevinError,\n SessionEventReducer,\n type CloudDevin,\n type CloudSession,\n type CloudSessionOptions,\n type PromptInput,\n type PromptResult,\n type SessionEvent,\n} from \"@cognition-ai/sdk\";\nimport { callable } from \"agents\";\nimport {\n createUIMessageStream,\n createUIMessageStreamResponse,\n isToolUIPart,\n type InferUIMessageChunk,\n type UIMessage,\n} from \"ai\";\n\nimport { connectDevin as connectFromEnv, type DevinEnv } from \"./connect.js\";\nimport { initialDevinChatState, reduceDevinChatState, type DevinChatState } from \"./state.js\";\n\n/** The messages a {@link DevinChatAgent} streams: `useAgentChat<DevinChatMessage>()`. */\nexport type DevinChatMessage = DevinUIMessage<DevinMessageMetadata>;\n\ntype DevinChatChunk = InferUIMessageChunk<DevinChatMessage>;\n\n/** What {@link DevinChatAgent.importSession} rebuilt. */\nexport interface ImportedSession {\n sessionId: string;\n sessionUrl: string | null;\n /** The first user message's text, e.g. for a chat title. */\n title: string | null;\n /** How many messages the replay produced. */\n messages: number;\n}\n\n/**\n * An `AIChatAgent` backed by a Devin cloud session instead of a model, so\n * `useAgentChat` drives Devin unchanged.\n *\n * - Each chat message prompts the chat's Devin session and streams the turn\n * with `@cognition-ai/ai-sdk`'s `toUIMessageStream`: text, reasoning, tool\n * calls, plans and pull requests.\n * - The session id lives in Agent state, so later turns attach to the same\n * session after hibernation, a deploy or from another client. Devin keeps\n * working in the cloud between turns.\n * - Permission requests are AI SDK tool approvals. `addToolApprovalResponse`\n * answers them and Cloudflare's auto-continuation resumes the turn.\n * - Stopping the client cancels the Devin turn; {@link startOver} detaches.\n *\n * ```ts\n * export class DevinChat extends DevinChatAgent<Env> {}\n * ```\n *\n * reads `DEVIN_API_KEY` (and optional `DEVIN_ORG_ID`, `DEVIN_BASE_URL`) from\n * the Worker's bindings. Override {@link connectDevin} for per-user tokens.\n */\nexport class DevinChatAgent<\n Env extends Cloudflare.Env & DevinEnv = Cloudflare.Env & DevinEnv,\n> extends AIChatAgent<Env, DevinChatState> {\n override initialState: DevinChatState = initialDevinChatState;\n /** A Devin session runs one turn at a time, so messages sent mid-turn wait their turn. */\n override messageConcurrency = \"queue\" as const;\n\n #turn: Turn | undefined;\n /** Bumped whenever the running turn is replaced, so its late events can't touch state. */\n #epoch = 0;\n\n /** Open the Devin connection a turn uses. Override for per-user tokens or other options. */\n protected connectDevin(): Promise<CloudDevin> {\n return connectFromEnv(this.env);\n }\n\n /** Options for the session the first turn creates, e.g. `{ repos: [\"acme/app\"] }`. */\n protected sessionOptions(): Omit<CloudSessionOptions, \"onPermission\"> {\n return {};\n }\n\n override onChatMessage(_onFinish: unknown, options?: OnChatMessageOptions): Promise<Response> {\n const signal = options?.abortSignal;\n const turn = this.#turn;\n const resumed = turn?.approvals.respond(this.messages);\n if (turn !== undefined && resumed !== undefined) {\n turn.follow(signal);\n return Promise.resolve(createUIMessageStreamResponse({ stream: resumed }));\n }\n if (options?.continuation === true) {\n return Promise.resolve(createUIMessageStreamResponse({ stream: this.#settleOrphans() }));\n }\n this.#replaceTurn();\n return Promise.resolve(createUIMessageStreamResponse({ stream: this.#prompt(signal) }));\n }\n\n /**\n * Detach from the Devin session so the next message starts a new one, and\n * stop the running turn. The old session keeps running in the cloud. Clear\n * the transcript on the client with `clearHistory()`.\n */\n @callable()\n startOver(): void {\n this.#replaceTurn();\n this.resetTurnState();\n this.setState(initialDevinChatState);\n }\n\n /**\n * Start this chat from an existing cloud session: rebuild its transcript\n * from the replayed tail and attach future turns to it.\n *\n * @throws {DevinError} when the chat already has a session or messages, or\n * the session can't be loaded.\n */\n async importSession(sessionId: string): Promise<ImportedSession> {\n if (this.state.sessionId !== null || this.messages.length > 0) {\n throw new DevinError(\"This chat already has a Devin session.\");\n }\n const loaded = await this.#load(sessionId);\n const messages = await toUIMessages(loaded.replay);\n const reducer = new SessionEventReducer();\n let state: DevinChatState = {\n ...initialDevinChatState,\n sessionId: loaded.sessionId,\n sessionUrl: loaded.sessionUrl,\n };\n for (const update of loaded.replay) state = reduceDevinChatState(state, reducer.handle(update));\n\n await this.persistMessages(messages);\n this.setState(state);\n const first = messages.find((message) => message.role === \"user\");\n const title = first?.parts\n .flatMap((part) => (part.type === \"text\" ? [part.text] : []))\n .join(\" \");\n return {\n sessionId: loaded.sessionId,\n sessionUrl: loaded.sessionUrl,\n title: title === undefined || title === \"\" ? null : title,\n messages: messages.length,\n };\n }\n\n /**\n * A Durable Object restart interrupted a turn. Keep what streamed, but don't\n * send the prompt again: Devin already has it and keeps working in the cloud.\n */\n protected override onChatRecovery(_ctx: ChatRecoveryContext): Promise<ChatRecoveryOptions> {\n return Promise.resolve({ persist: true, continue: false });\n }\n\n #prompt(signal: AbortSignal | undefined): ReadableStream<DevinChatChunk> {\n const epoch = this.#epoch;\n return createUIMessageStream<DevinChatMessage>({\n onError: errorText,\n execute: async ({ writer }) => {\n const prompt = toPromptInput(this.messages);\n const devin = await this.connectDevin();\n let session: CloudSession;\n try {\n session = await this.#openSession(devin, epoch);\n } catch (error) {\n devin.close();\n throw error;\n }\n if (signal?.aborted === true || epoch !== this.#epoch) {\n devin.close();\n return;\n }\n const turn = new Turn(devin, session, () => {\n if (this.#turn === turn) this.#turn = undefined;\n });\n this.#turn = turn;\n turn.follow(signal);\n writer.merge(\n toUIMessageStream(turn.events(prompt, toolCallIds(this.messages)), {\n approvals: turn.approvals,\n messageMetadata: devinSessionMetadata(session),\n onError: errorText,\n onEvent: (event) => {\n this.#project(epoch, session, event);\n },\n }),\n );\n },\n });\n }\n\n async #openSession(devin: CloudDevin, epoch: number): Promise<CloudSession> {\n const { sessionId } = this.state;\n if (sessionId !== null) return devin.attach(sessionId);\n const session = await devin.createSession(this.sessionOptions());\n if (epoch === this.#epoch) {\n this.setState({ ...this.state, sessionId: session.id, sessionUrl: session.url ?? null });\n }\n return session;\n }\n\n #project(epoch: number, session: CloudSession, event: SessionEvent): void {\n if (epoch !== this.#epoch || this.state.sessionId !== session.id) return;\n let next = reduceDevinChatState(this.state, event);\n const url = session.url ?? next.sessionUrl;\n if (url !== next.sessionUrl) next = { ...next, sessionUrl: url };\n if (next !== this.state) this.setState(next);\n }\n\n /** Stop the running turn and fence off its late events. */\n #replaceTurn(): void {\n this.#epoch++;\n const turn = this.#turn;\n this.#turn = undefined;\n turn?.stop();\n }\n\n /**\n * An approval arrived for a turn this agent no longer holds (it was stopped,\n * or the Durable Object restarted). End those tool calls instead of leaving\n * them spinning.\n */\n #settleOrphans(): ReadableStream<DevinChatChunk> {\n const last = this.messages.at(-1);\n const parts = last?.role === \"assistant\" ? last.parts.filter(isToolUIPart) : [];\n return createUIMessageStream<DevinChatMessage>({\n execute: ({ writer }) => {\n writer.write({ type: \"start\" });\n for (const part of parts) {\n if (part.state !== \"approval-responded\") continue;\n writer.write({\n type: \"tool-output-error\",\n toolCallId: part.toolCallId,\n errorText: \"This Devin turn ended before the approval arrived.\",\n dynamic: true,\n });\n }\n writer.write({ type: \"finish\", finishReason: \"other\" });\n },\n });\n }\n\n async #load(\n sessionId: string,\n ): Promise<{ sessionId: string; sessionUrl: string | null; replay: LoadedReplay }> {\n await using devin = await this.connectDevin();\n try {\n const { session, replay } = await devin.loadSession(sessionId, { replay: \"tail\" });\n return { sessionId: session.id, sessionUrl: session.url ?? null, replay };\n } catch (error) {\n throw new DevinError(`Could not load Devin session ${sessionId}: ${errorText(error)}`);\n }\n }\n}\n\ntype LoadedReplay = Awaited<ReturnType<CloudDevin[\"loadSession\"]>>[\"replay\"];\n\n/** One Devin turn: its connection, its approvals, and a way to stop it. */\nclass Turn {\n readonly approvals = new ToolApprovals();\n readonly #devin: CloudDevin;\n readonly #session: CloudSession;\n readonly #stop = new AbortController();\n readonly #onClose: () => void;\n #started = false;\n #closed = false;\n\n constructor(devin: CloudDevin, session: CloudSession, onClose: () => void) {\n this.#devin = devin;\n this.#session = session;\n this.#onClose = onClose;\n session.onPermission = this.approvals.onPermission;\n }\n\n /**\n * The turn's events, minus updates for tool calls that belong to an earlier\n * message: stopping a turn does not stop the command Devin was running, so\n * it can finish during a later turn. Its part lives in a message this\n * stream can't reach, and `AIChatAgent` folds messages that share a tool\n * call id into one, which would overwrite the earlier reply.\n */\n async *events(\n prompt: PromptInput,\n earlierToolCalls: ReadonlySet<string>,\n ): AsyncGenerator<SessionEvent, PromptResult> {\n this.#started = true;\n const turn = this.#session.stream(prompt, { signal: this.#stop.signal });\n let finished = false;\n try {\n for (;;) {\n const next = await turn.next();\n if (next.done) {\n finished = true;\n return next.value;\n }\n const event = next.value;\n if (event.type === \"tool_call\" && earlierToolCalls.has(event.call.id)) continue;\n yield event;\n }\n } finally {\n // The consumer stopped early: let the SDK's generator run its cleanup too.\n if (!finished) await turn.return(undefined as never);\n this.#close();\n }\n }\n\n /** Stop the turn when this request's signal aborts (the client pressed stop). */\n follow(signal: AbortSignal | undefined): void {\n if (signal === undefined) return;\n if (signal.aborted) {\n this.stop();\n return;\n }\n signal.addEventListener(\n \"abort\",\n () => {\n this.stop();\n },\n { once: true },\n );\n }\n\n stop(): void {\n this.#stop.abort(new DevinError(\"The Devin turn was stopped.\"));\n this.approvals.cancel();\n if (!this.#started) this.#close();\n }\n\n #close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.approvals.cancel();\n this.#devin.close();\n this.#onClose();\n }\n}\n\n/** Ids of every tool call in the transcript so far. */\nfunction toolCallIds(messages: readonly UIMessage[]): Set<string> {\n const ids = new Set<string>();\n for (const message of messages) {\n for (const part of message.parts) if (isToolUIPart(part)) ids.add(part.toolCallId);\n }\n return ids;\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"devin-chat-agent.js","sourceRoot":"","sources":["../src/devin-chat-agent.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AIChatAgent,\n type ChatRecoveryContext,\n type ChatRecoveryOptions,\n type OnChatMessageOptions,\n} from \"@cloudflare/ai-chat\";\nimport {\n devinSessionMetadata,\n toPromptInput,\n toUIMessages,\n toUIMessageStream,\n ToolApprovals,\n type DevinMessageMetadata,\n type DevinUIMessage,\n} from \"@cognition-ai/ai-sdk\";\nimport {\n DevinError,\n SessionEventReducer,\n type CloudDevin,\n type CloudSession,\n type CloudSessionOptions,\n type PromptInput,\n type PromptResult,\n type SessionEvent,\n type SessionUpdate,\n} from \"@cognition-ai/sdk\";\nimport { callable } from \"agents\";\nimport {\n createUIMessageStream,\n createUIMessageStreamResponse,\n isToolUIPart,\n type InferUIMessageChunk,\n type UIMessage,\n} from \"ai\";\n\nimport { connectDevin as connectFromEnv, type DevinEnv } from \"./connect.js\";\nimport { initialDevinChatState, reduceDevinChatState, type DevinChatState } from \"./state.js\";\n\n/** The messages a {@link DevinChatAgent} streams: `useAgentChat<DevinChatMessage>()`. */\nexport type DevinChatMessage = DevinUIMessage<DevinMessageMetadata>;\n\ntype DevinChatChunk = InferUIMessageChunk<DevinChatMessage>;\n\n/** What {@link DevinChatAgent.importSession} rebuilt. */\nexport interface ImportedSession {\n sessionId: string;\n sessionUrl: string | null;\n /** The first user message's text, e.g. for a chat title. */\n title: string | null;\n /** How many messages the replay produced. */\n messages: number;\n}\n\n/**\n * An `AIChatAgent` backed by a Devin cloud session instead of a model, so\n * `useAgentChat` drives Devin unchanged.\n *\n * - Each chat message prompts the chat's Devin session and streams the turn\n * with `@cognition-ai/ai-sdk`'s `toUIMessageStream`: text, reasoning, tool\n * calls, plans and pull requests.\n * - The session id lives in Agent state, so later turns attach to the same\n * session after hibernation, a deploy or from another client. Devin keeps\n * working in the cloud between turns.\n * - Permission requests are AI SDK tool approvals. `addToolApprovalResponse`\n * answers them and Cloudflare's auto-continuation resumes the turn.\n * - Stopping the client cancels the Devin turn; {@link startOver} detaches.\n *\n * ```ts\n * export class DevinChat extends DevinChatAgent<Env> {}\n * ```\n *\n * reads `DEVIN_API_KEY` (and optional `DEVIN_ORG_ID`, `DEVIN_BASE_URL`) from\n * the Worker's bindings. Override {@link connectDevin} for per-user tokens.\n */\nexport class DevinChatAgent<\n Env extends Cloudflare.Env & DevinEnv = Cloudflare.Env & DevinEnv,\n> extends AIChatAgent<Env, DevinChatState> {\n override initialState: DevinChatState = initialDevinChatState;\n /** A Devin session runs one turn at a time, so messages sent mid-turn wait their turn. */\n override messageConcurrency = \"queue\" as const;\n\n #turn: Turn | undefined;\n /** Bumped whenever the running turn is replaced, so its late events can't touch state. */\n #epoch = 0;\n\n /** Open the Devin connection a turn uses. Override for per-user tokens or other options. */\n protected connectDevin(): Promise<CloudDevin> {\n return connectFromEnv(this.env);\n }\n\n /** Options for the session the first turn creates, e.g. `{ repos: [\"acme/app\"] }`. */\n protected sessionOptions(): Omit<CloudSessionOptions, \"onPermission\"> {\n return {};\n }\n\n override onChatMessage(_onFinish: unknown, options?: OnChatMessageOptions): Promise<Response> {\n const signal = options?.abortSignal;\n const turn = this.#turn;\n const resumed = turn?.approvals.respond(this.messages);\n if (turn !== undefined && resumed !== undefined) {\n turn.follow(signal);\n return Promise.resolve(createUIMessageStreamResponse({ stream: resumed }));\n }\n if (options?.continuation === true) {\n return Promise.resolve(createUIMessageStreamResponse({ stream: this.#settleOrphans() }));\n }\n this.#replaceTurn();\n return Promise.resolve(createUIMessageStreamResponse({ stream: this.#prompt(signal) }));\n }\n\n /**\n * Detach from the Devin session so the next message starts a new one, and\n * stop the running turn. The old session keeps running in the cloud. Clear\n * the transcript on the client with `clearHistory()`.\n */\n @callable()\n startOver(): void {\n this.#replaceTurn();\n this.resetTurnState();\n this.setState(initialDevinChatState);\n }\n\n /**\n * Start this chat from an existing cloud session: rebuild its transcript\n * from the replayed tail and attach future turns to it.\n *\n * @throws {DevinError} when the chat already has a session or messages, or\n * the session can't be loaded.\n */\n async importSession(sessionId: string): Promise<ImportedSession> {\n if (this.state.sessionId !== null || this.messages.length > 0) {\n throw new DevinError(\"This chat already has a Devin session.\");\n }\n const loaded = await this.#load(sessionId);\n const messages = await toUIMessages(loaded.replay);\n const reducer = new SessionEventReducer();\n let state: DevinChatState = {\n ...initialDevinChatState,\n sessionId: loaded.sessionId,\n sessionUrl: loaded.sessionUrl,\n };\n for (const update of loaded.replay) state = reduceDevinChatState(state, reducer.handle(update));\n\n await this.persistMessages(messages);\n this.setState(state);\n const first = messages.find((message) => message.role === \"user\");\n const title = first?.parts\n .flatMap((part) => (part.type === \"text\" ? [part.text] : []))\n .join(\" \");\n return {\n sessionId: loaded.sessionId,\n sessionUrl: loaded.sessionUrl,\n title: title === undefined || title === \"\" ? null : title,\n messages: messages.length,\n };\n }\n\n /**\n * A Durable Object restart interrupted a turn. Keep what streamed, but don't\n * send the prompt again: Devin already has it and keeps working in the cloud.\n */\n protected override onChatRecovery(_ctx: ChatRecoveryContext): Promise<ChatRecoveryOptions> {\n return Promise.resolve({ persist: true, continue: false });\n }\n\n #prompt(signal: AbortSignal | undefined): ReadableStream<DevinChatChunk> {\n const epoch = this.#epoch;\n return createUIMessageStream<DevinChatMessage>({\n onError: errorText,\n execute: async ({ writer }) => {\n const prompt = toPromptInput(this.messages);\n const devin = await this.connectDevin();\n let session: CloudSession;\n try {\n session = await this.#openSession(devin, epoch);\n } catch (error) {\n devin.close();\n throw error;\n }\n if (signal?.aborted === true || epoch !== this.#epoch) {\n devin.close();\n return;\n }\n const turn = new Turn(devin, session, () => {\n if (this.#turn === turn) this.#turn = undefined;\n });\n this.#turn = turn;\n turn.follow(signal);\n writer.merge(\n toUIMessageStream(turn.events(prompt, toolCallIds(this.messages)), {\n approvals: turn.approvals,\n messageMetadata: devinSessionMetadata(session),\n onEvent: (event) => {\n this.#project(epoch, session, event);\n },\n }),\n );\n },\n });\n }\n\n async #openSession(devin: CloudDevin, epoch: number): Promise<CloudSession> {\n const { sessionId } = this.state;\n if (sessionId !== null) return devin.attach(sessionId);\n const session = await devin.createSession(this.sessionOptions());\n if (epoch === this.#epoch) {\n this.setState({ ...this.state, sessionId: session.id, sessionUrl: session.url ?? null });\n }\n return session;\n }\n\n #project(epoch: number, session: CloudSession, event: SessionEvent): void {\n if (epoch !== this.#epoch || this.state.sessionId !== session.id) return;\n let next = reduceDevinChatState(this.state, event);\n const url = session.url ?? next.sessionUrl;\n if (url !== next.sessionUrl) next = { ...next, sessionUrl: url };\n if (next !== this.state) this.setState(next);\n }\n\n /** Stop the running turn and fence off its late events. */\n #replaceTurn(): void {\n this.#epoch++;\n const turn = this.#turn;\n this.#turn = undefined;\n turn?.stop();\n }\n\n /**\n * An approval arrived for a turn this agent no longer holds (it was stopped,\n * or the Durable Object restarted). End those tool calls instead of leaving\n * them spinning.\n */\n #settleOrphans(): ReadableStream<DevinChatChunk> {\n const last = this.messages.at(-1);\n const parts = last?.role === \"assistant\" ? last.parts.filter(isToolUIPart) : [];\n return createUIMessageStream<DevinChatMessage>({\n execute: ({ writer }) => {\n writer.write({ type: \"start\" });\n for (const part of parts) {\n if (part.state !== \"approval-responded\") continue;\n writer.write({\n type: \"tool-output-error\",\n toolCallId: part.toolCallId,\n errorText: \"This Devin turn ended before the approval arrived.\",\n dynamic: true,\n });\n }\n writer.write({ type: \"finish\", finishReason: \"other\" });\n },\n });\n }\n\n async #load(\n sessionId: string,\n ): Promise<{ sessionId: string; sessionUrl: string | null; replay: SessionUpdate[] }> {\n await using devin = await this.connectDevin();\n try {\n const { session, replay } = await devin.loadSession(sessionId, { replay: \"tail\" });\n return { sessionId: session.id, sessionUrl: session.url ?? null, replay };\n } catch (error) {\n throw new DevinError(`Could not load Devin session ${sessionId}: ${errorText(error)}`);\n }\n }\n}\n\n/** One Devin turn: its connection, its approvals, and a way to stop it. */\nclass Turn {\n readonly approvals = new ToolApprovals();\n readonly #devin: CloudDevin;\n readonly #session: CloudSession;\n readonly #stop = new AbortController();\n readonly #onClose: () => void;\n #started = false;\n #closed = false;\n\n constructor(devin: CloudDevin, session: CloudSession, onClose: () => void) {\n this.#devin = devin;\n this.#session = session;\n this.#onClose = onClose;\n session.onPermission = this.approvals.onPermission;\n }\n\n /**\n * The turn's events, minus updates for tool calls that belong to an earlier\n * message: stopping a turn does not stop the command Devin was running, so\n * it can finish during a later turn. Its part lives in a message this\n * stream can't reach, and `AIChatAgent` folds messages that share a tool\n * call id into one, which would overwrite the earlier reply.\n */\n async *events(\n prompt: PromptInput,\n earlierToolCalls: ReadonlySet<string>,\n ): AsyncGenerator<SessionEvent, PromptResult> {\n this.#started = true;\n const turn = this.#session.stream(prompt, { signal: this.#stop.signal });\n try {\n for (;;) {\n const next = await turn.next();\n if (next.done) return next.value;\n const event = next.value;\n if (event.type === \"tool_call\" && earlierToolCalls.has(event.call.id)) continue;\n yield event;\n }\n } finally {\n // If the consumer stopped early, let the SDK's generator run its cleanup too.\n await turn.return(undefined as never);\n this.#close();\n }\n }\n\n /** Stop the turn when this request's signal aborts (the client pressed stop). */\n follow(signal: AbortSignal | undefined): void {\n if (signal === undefined) return;\n if (signal.aborted) {\n this.stop();\n return;\n }\n signal.addEventListener(\n \"abort\",\n () => {\n this.stop();\n },\n { once: true },\n );\n }\n\n stop(): void {\n this.#stop.abort(new DevinError(\"The Devin turn was stopped.\"));\n this.approvals.cancel();\n if (!this.#started) this.#close();\n }\n\n #close(): void {\n if (this.#closed) return;\n this.#closed = true;\n this.approvals.cancel();\n this.#devin.close();\n this.#onClose();\n }\n}\n\n/** Ids of every tool call in the transcript so far. */\nfunction toolCallIds(messages: readonly UIMessage[]): Set<string> {\n const ids = new Set<string>();\n for (const message of messages) {\n for (const part of message.parts) if (isToolUIPart(part)) ids.add(part.toolCallId);\n }\n return ids;\n}\n\nfunction errorText(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cognition-ai/cloudflare-agents",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.5",
|
|
4
4
|
"description": "Cloudflare Agents adapter for the Devin SDK: a Devin cloud session behind an AIChatAgent, for useAgentChat.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"test": "vitest run --config test/vitest.config.ts"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@cognition-ai/ai-sdk": "0.0.1-beta.
|
|
31
|
-
"@cognition-ai/sdk": "0.0.1-beta.
|
|
30
|
+
"@cognition-ai/ai-sdk": "0.0.1-beta.5",
|
|
31
|
+
"@cognition-ai/sdk": "0.0.1-beta.5"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@cloudflare/ai-chat": ">=0.11.0 <1.0.0",
|