feat: Slice 1 polish - MiMo V2.5 model, visible reasoning, image attachments, mobile keyboard fix

- Switch conversation agent to xiaomi/mimo-v2.5 (multimodal: text + image)
- Render native reasoning parts as live 'Thinking trace' (streaming open,
  collapsed after completion); inline <think> extraction for streaming models
- Image attachments: picker (up to 4, 10MB each), base64 to Flue
  AgentPromptImage, authenticated blob-URL replay for historical images
- Mobile keyboard viewport fix: visual-viewport hook, fixed shell,
  interactive-widget=resizes-content, header pinned, composer follows keyboard
- Conversation to Signal to proposed Work: Convex persistence, Effect
  validation in @code/work-os, Work cards with exact source provenance
- Streamdown markdown + Mermaid chart rendering in chat messages
- Flue tool turns hidden, reasoning-containing turns remain visible
- Frontend regression tests: keyboard viewport, responsive shell,
  attachment overflow, authenticated images, reasoning traces, transforms
- .env.example updated to xiaomi/mimo-v2.5 config
This commit is contained in:
-Puter
2026-07-27 12:22:54 +05:30
parent 58ff7942bd
commit d8383a788e
55 changed files with 6487 additions and 2006 deletions

View File

@@ -0,0 +1,224 @@
import { env } from "@code/env/convex";
import { convexTest } from "convex-test";
import { anyApi } from "convex/server";
import { describe, expect, test } from "vitest";
import { internal } from "./_generated/api";
import schema from "./schema";
declare global {
interface ImportMeta {
readonly glob: (pattern: string) => Record<string, () => Promise<unknown>>;
}
}
const modules = import.meta.glob("./**/*.ts");
const api = anyApi;
const identity = { tokenIdentifier: "https://convex.test|slice-one" };
describe("Slice 1 Work routing", () => {
test("creates one proposed Work and preserves exact source text", async () => {
const t = convexTest({ schema, modules });
const organization = await t
.withIdentity(identity)
.mutation(api.organizations.ensurePersonalOrganization, {});
const project = await t
.withIdentity(identity)
.mutation(internal.projects.persistPublicGitImport, {
remote: { defaultBranch: "main", documents: [], warnings: [] },
source: {
host: "github.com",
normalizedUrl: "https://github.com/example/slice-one",
projectName: "slice-one",
repositoryPath: "example/slice-one",
url: "https://github.com/example/slice-one",
},
userId: identity.tokenIdentifier,
});
const rawText = " Add a phone-ready Slice 1 experience. ";
const message = await t
.withIdentity(identity)
.mutation(api.conversationMessages.beginUserMessage, {
clientRequestId: "slice-one-request",
organizationId: organization._id,
rawText,
});
await t
.withIdentity(identity)
.mutation(api.conversationMessages.markAdmitted, {
clientRequestId: "slice-one-request",
organizationId: organization._id,
submissionId: "slice-one-submission",
});
const signal = await t.mutation(api.signalRouting.createSignal, {
messageIds: [message.messageId],
organizationId: organization._id,
problemStatement: {
constraints: ["Mobile web first"],
desiredOutcome: "The Slice 1 loop works on a phone.",
summary: "The current product is not ready for phone testing.",
title: "Make Slice 1 phone-ready",
},
processedByAgentInstanceId: organization._id,
projectId: project.id,
token: env.FLUE_DB_TOKEN,
});
const first = await t.mutation(api.works.createFromSignal, {
organizationId: organization._id,
signalId: signal.signalId,
token: env.FLUE_DB_TOKEN,
});
const repeated = await t.mutation(api.works.createFromSignal, {
organizationId: organization._id,
signalId: signal.signalId,
token: env.FLUE_DB_TOKEN,
});
expect(repeated).toEqual({ created: false, workId: first.workId });
const works = await t
.withIdentity(identity)
.query(api.works.listForProject, { projectId: project.id });
expect(works).toHaveLength(1);
expect(works[0]?.status).toBe("proposed");
expect(works[0]?.signals[0]?.sources[0]?.rawText).toBe(rawText);
});
test("keeps casual conversation out of Work", async () => {
const t = convexTest({ schema, modules });
const organization = await t
.withIdentity(identity)
.mutation(api.organizations.ensurePersonalOrganization, {});
const project = await t
.withIdentity(identity)
.mutation(internal.projects.persistPublicGitImport, {
remote: { defaultBranch: "main", documents: [], warnings: [] },
source: {
host: "git.openputer.com",
normalizedUrl: "https://git.openputer.com/puter/zopu-code",
projectName: "zopu-code",
repositoryPath: "puter/zopu-code",
url: "https://git.openputer.com/puter/zopu-code",
},
userId: identity.tokenIdentifier,
});
await t
.withIdentity(identity)
.mutation(api.conversationMessages.beginUserMessage, {
clientRequestId: "slice-one-casual",
organizationId: organization._id,
rawText: "Yo, how are you?",
});
await t
.withIdentity(identity)
.mutation(api.conversationMessages.markAdmitted, {
clientRequestId: "slice-one-casual",
organizationId: organization._id,
submissionId: "slice-one-casual-submission",
});
const works = await t
.withIdentity(identity)
.query(api.works.listForProject, { projectId: project.id });
expect(works).toEqual([]);
});
test("attaches another Signal to existing Work idempotently", async () => {
const t = convexTest({ schema, modules });
const organization = await t
.withIdentity(identity)
.mutation(api.organizations.ensurePersonalOrganization, {});
const project = await t
.withIdentity(identity)
.mutation(internal.projects.persistPublicGitImport, {
remote: { defaultBranch: "main", documents: [], warnings: [] },
source: {
host: "git.openputer.com",
normalizedUrl: "https://git.openputer.com/puter/zopu-code",
projectName: "zopu-code",
repositoryPath: "puter/zopu-code",
url: "https://git.openputer.com/puter/zopu-code",
},
userId: identity.tokenIdentifier,
});
const seedSignal = async (
clientRequestId: string,
rawText: string,
title: string
) => {
const message = await t
.withIdentity(identity)
.mutation(api.conversationMessages.beginUserMessage, {
clientRequestId,
organizationId: organization._id,
rawText,
});
await t
.withIdentity(identity)
.mutation(api.conversationMessages.markAdmitted, {
clientRequestId,
organizationId: organization._id,
submissionId: `${clientRequestId}-submission`,
});
return await t.mutation(api.signalRouting.createSignal, {
messageIds: [message.messageId],
organizationId: organization._id,
problemStatement: {
constraints: [],
desiredOutcome: "The Slice 1 phone flow is polished.",
summary: "The messages describe the same desired outcome.",
title,
},
processedByAgentInstanceId: organization._id,
projectId: project.id,
token: env.FLUE_DB_TOKEN,
});
};
const firstSignal = await seedSignal(
"slice-one-first",
"Polish the Slice 1 phone experience.",
"Polish Slice 1"
);
const secondSignal = await seedSignal(
"slice-one-second",
"Make the same Slice 1 experience easier to inspect on mobile.",
"Improve Slice 1 inspection"
);
const created = await t.mutation(api.works.createFromSignal, {
organizationId: organization._id,
signalId: firstSignal.signalId,
token: env.FLUE_DB_TOKEN,
});
const firstAttach = await t.mutation(api.works.attachSignalToWork, {
organizationId: organization._id,
signalId: secondSignal.signalId,
token: env.FLUE_DB_TOKEN,
workId: created.workId,
});
const repeatedAttach = await t.mutation(api.works.attachSignalToWork, {
organizationId: organization._id,
signalId: secondSignal.signalId,
token: env.FLUE_DB_TOKEN,
workId: created.workId,
});
expect(firstAttach).toEqual({ attached: true, workId: created.workId });
expect(repeatedAttach).toEqual({
attached: false,
workId: created.workId,
});
const works = await t
.withIdentity(identity)
.query(api.works.listForProject, { projectId: project.id });
expect(works).toHaveLength(1);
expect(works[0]?.signals).toHaveLength(2);
expect(
works[0]?.events.filter(
(event: { readonly kind: string }) => event.kind === "signal.attached"
)
).toHaveLength(1);
});
});