Skip to content
2 changes: 1 addition & 1 deletion apps/server/src/git/Services/TextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { ChatAttachment, ModelSelection } from "@t3tools/contracts";
import type { TextGenerationError } from "../Errors.ts";

/** Providers that support git text generation (commit messages, PR content, branch names). */
export type TextGenerationProvider = "codex" | "claudeAgent";
export type TextGenerationProvider = "codex" | "claudeAgent" | "droid";

export interface CommitMessageGenerationInput {
cwd: string;
Expand Down
241 changes: 240 additions & 1 deletion apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ describe("ProviderRuntimeIngestion", () => {
});

it("buffers assistant deltas by default until completion", async () => {
const harness = await createHarness();
const harness = await createHarness({ serverSettings: { enableAssistantStreaming: false } });
const now = new Date().toISOString();

harness.emit({
Expand Down Expand Up @@ -1486,6 +1486,243 @@ describe("ProviderRuntimeIngestion", () => {
expect(finalMessage?.streaming).toBe(false);
});

it("stitches Droid assistant token fragments back into spaced text", async () => {
const harness = await createHarness({ serverSettings: { enableAssistantStreaming: true } });
const now = new Date().toISOString();

harness.emit({
type: "turn.started",
eventId: asEventId("evt-turn-started-droid-spacing"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
});
await waitForThread(
harness.engine,
(thread) =>
thread.session?.status === "running" &&
thread.session?.activeTurnId === "turn-droid-spacing",
);

harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-1"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "I'm",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-2"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "Droid, an AI software engineering agent",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-3"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "built by Factory.",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-4"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "Right",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-5"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "now I'm sitting in your",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-6"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "`apps",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-spacing-7"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
streamKind: "assistant_text",
delta: "/server` directory.",
},
});

const liveThread = await waitForThread(harness.engine, (entry) =>
entry.messages.some(
(message: ProviderRuntimeTestMessage) =>
message.id === "assistant:item-droid-spacing" && message.streaming,
),
);
const liveMessage = liveThread.messages.find(
(entry: ProviderRuntimeTestMessage) => entry.id === "assistant:item-droid-spacing",
);
expect(liveMessage?.streaming).toBe(true);

harness.emit({
type: "item.completed",
eventId: asEventId("evt-message-completed-droid-spacing"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-spacing"),
itemId: asItemId("item-droid-spacing"),
payload: {
itemType: "assistant_message",
status: "completed",
},
});

const finalThread = await waitForThread(harness.engine, (entry) =>
entry.messages.some(
(message: ProviderRuntimeTestMessage) =>
message.id === "assistant:item-droid-spacing" && !message.streaming,
),
);
const finalMessage = finalThread.messages.find(
(entry: ProviderRuntimeTestMessage) => entry.id === "assistant:item-droid-spacing",
);
expect(finalMessage?.text).toBe(
"I'm Droid, an AI software engineering agent built by Factory. Right now I'm sitting in your `apps/server` directory.",
);
expect(finalMessage?.streaming).toBe(false);
});

it("does not inject spaces into open double-backtick Droid inline code spans", async () => {
const harness = await createHarness({ serverSettings: { enableAssistantStreaming: true } });
const now = new Date().toISOString();

harness.emit({
type: "turn.started",
eventId: asEventId("evt-turn-started-droid-double-backtick"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-double-backtick"),
});
await waitForThread(
harness.engine,
(thread) =>
thread.session?.status === "running" &&
thread.session?.activeTurnId === "turn-droid-double-backtick",
);

harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-double-backtick-1"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-double-backtick"),
itemId: asItemId("item-droid-double-backtick"),
payload: {
streamKind: "assistant_text",
delta: "Here is ``",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-double-backtick-2"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-double-backtick"),
itemId: asItemId("item-droid-double-backtick"),
payload: {
streamKind: "assistant_text",
delta: "code span",
},
});
harness.emit({
type: "content.delta",
eventId: asEventId("evt-message-delta-droid-double-backtick-3"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-double-backtick"),
itemId: asItemId("item-droid-double-backtick"),
payload: {
streamKind: "assistant_text",
delta: "`` done",
},
});

harness.emit({
type: "item.completed",
eventId: asEventId("evt-message-completed-droid-double-backtick"),
provider: "droid",
createdAt: now,
threadId: asThreadId("thread-1"),
turnId: asTurnId("turn-droid-double-backtick"),
itemId: asItemId("item-droid-double-backtick"),
payload: {
itemType: "assistant_message",
status: "completed",
},
});

const finalThread = await waitForThread(harness.engine, (entry) =>
entry.messages.some(
(message: ProviderRuntimeTestMessage) =>
message.id === "assistant:item-droid-double-backtick" && !message.streaming,
),
);
const finalMessage = finalThread.messages.find(
(entry: ProviderRuntimeTestMessage) => entry.id === "assistant:item-droid-double-backtick",
);
expect(finalMessage?.text).toBe("Here is ``code span`` done");
expect(finalMessage?.streaming).toBe(false);
});

it("spills oversized buffered deltas and still finalizes full assistant text", async () => {
const harness = await createHarness();
const now = new Date().toISOString();
Expand Down Expand Up @@ -1967,7 +2204,9 @@ describe("ProviderRuntimeIngestion", () => {
: undefined;
expect(toolUpdate?.kind).toBe("tool.updated");
expect(toolUpdatePayload?.itemType).toBe("command_execution");
expect(toolUpdatePayload?.title).toBe("Run tests");
expect(toolUpdatePayload?.status).toBe("in_progress");
expect(toolUpdatePayload?.detail).toBe("bun test");

const warning = thread.activities.find(
(activity: ProviderRuntimeTestActivity) => activity.id === "evt-runtime-warning",
Expand Down
Loading
Loading