Integrate mobile chat workspace and OpenRouter agent flow

This commit is contained in:
sai karthik
2026-07-25 17:49:11 +05:30
parent a17aa5c283
commit 48200a11df
24 changed files with 1142 additions and 211 deletions

View File

@@ -2,7 +2,6 @@ import path from "node:path";
import { parseAgentEnv } from "@code/env/agent";
import { defineAgent } from "@flue/runtime";
// import { agentos } from "../sandboxes/agentos";
import { local } from "@flue/runtime/node";

View File

@@ -9,18 +9,25 @@ const agentEnv = parseAgentEnv(process.env);
registerProvider(agentEnv.AGENT_MODEL_PROVIDER, {
api: agentEnv.AGENT_MODEL_API,
apiKey: agentEnv.AGENT_MODEL_API_KEY,
apiKey:
agentEnv.AGENT_MODEL_PROVIDER === "openrouter"
? (agentEnv.OPENROUTER_API_KEY ?? agentEnv.AGENT_MODEL_API_KEY)
: agentEnv.AGENT_MODEL_API_KEY,
baseUrl: agentEnv.AGENT_MODEL_BASE_URL,
models: {
[agentEnv.AGENT_MODEL_NAME]: {
contextWindow: agentEnv.AGENT_MODEL_CONTEXT_WINDOW,
maxTokens: agentEnv.AGENT_MODEL_MAX_TOKENS,
},
"openai/gpt-oss-20b:free": {
contextWindow: 131_072,
maxTokens: agentEnv.AGENT_MODEL_MAX_TOKENS,
},
},
});
const app = new Hono();
app.post("/project-requests", projectRequestRoute);
app.route("/", flue());
app.route("/", flue() as unknown as Hono);
export default app;

View File

@@ -317,4 +317,5 @@ export const authenticatedAgentRoute: AgentRouteHandler = async (c, next) => {
clientRequestId,
organizationId: organization._id,
});
return c.res;
};

View File

@@ -1,7 +1,9 @@
import { parseAgentEnv } from "@code/env/agent";
import { defineTool } from "@flue/runtime";
import { ProjectIssueDispatchInput } from "@code/primitives/project-issue";
import { defineTool, dispatch } from "@flue/runtime";
import { ConvexHttpClient } from "convex/browser";
import { makeFunctionReference } from "convex/server";
import { Schema } from "effect";
import * as v from "valibot";
// ---------------------------------------------------------------------------
@@ -103,9 +105,24 @@ const beginIssueRef = makeFunctionReference<
readonly issueId: string;
readonly token: string;
},
"queued" | "working"
{
readonly dispatchRequired: boolean;
readonly projectId: string;
readonly status: "queued" | "working";
}
>("signalRouting:beginIssue");
const markDispatchFailedRef = makeFunctionReference<
"mutation",
{
readonly error: string;
readonly issueId: string;
readonly organizationId: string;
readonly token: string;
},
null
>("signalRouting:markDispatchFailed");
const getProjectContextRef = makeFunctionReference<
"query",
{
@@ -306,11 +323,45 @@ export const createSignalRoutingTools = (
}),
name: "begin_issue",
async run({ input }) {
return await client.mutation(beginIssueRef, {
const outcome = await client.mutation(beginIssueRef, {
issueId: input.issueId,
organizationId,
token,
});
const dispatchInput = Schema.decodeUnknownSync(
ProjectIssueDispatchInput
)({
issueId: input.issueId,
kind: "project.issue.started",
projectId: outcome.projectId,
});
if (!outcome.dispatchRequired) {
return {
acceptedAt: "",
dispatchId: "",
status: outcome.status,
};
}
try {
const receipt = await dispatch({
agent: "project-manager",
id: input.issueId,
input: dispatchInput,
});
return {
acceptedAt: receipt.acceptedAt,
dispatchId: receipt.dispatchId,
status: outcome.status,
};
} catch (error) {
await client.mutation(markDispatchFailedRef, {
error: error instanceof Error ? error.message : String(error),
issueId: input.issueId,
organizationId,
token,
});
throw error;
}
},
}),
];