Skip to content

Conversation

@aka-sacci-ccr
Copy link

@aka-sacci-ccr aka-sacci-ccr commented Jan 14, 2026

Summary by cubic

Adds thread storage and tools for saving/retrieving conversation history, plus a generate-with-thread tool that merges context and auto-saves user/assistant messages. This enables persistent, per-thread LLM chats backed by Postgres.

  • New Features

    • PostgreSQL schema for threads and messages with indexes; created on config change.
    • SAVE_THREAD_DATA and RETRIEVE_THREAD_DATA tools; saves messages in user→assistant pairs and returns ordered pairs.
    • LLM_DO_GENERATE_WITH_THREAD: loads thread history, calls LLM_DO_GENERATE, persists the turn, and commits wallet usage.
    • Runtime wiring: registers thread tools, adds DATABASE binding to state, and scopes.
    • runSQL helper using DATABASE::DATABASES_RUN_SQL with basic param sanitization.
  • Migration

    • Configure the DATABASE binding (@deco/postgres) in Env.
    • Grant scope DATABASE::DATABASES_RUN_SQL.
    • Deploy or reload configuration to auto-create the threads tables.

Written for commit 40544ec. Summary will update on new commits.

@github-actions
Copy link

🚀 Preview Deployments Ready!

Your changes have been deployed to preview environments:

📦 deco-llm

🔗 View Preview

These previews will be automatically updated with new commits to this PR.


Deployed from commit: 50b0e4d

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 6 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="deco-llm/server/db/postgres.ts">

<violation number="1" location="deco-llm/server/db/postgres.ts:28">
P1: Missing optional chaining on `DATABASE`. If `state` exists but `DATABASE` is undefined, accessing `.DATABASES_RUN_SQL()` will throw.</violation>
</file>

<file name="deco-llm/server/tools/threads.ts">

<violation number="1" location="deco-llm/server/tools/threads.ts:247">
P2: JSON.parse without try-catch can throw on malformed data. If stored JSON is corrupted, this will crash the request. Consider wrapping in try-catch with fallback to null or logging the error.</violation>

<violation number="2" location="deco-llm/server/tools/threads.ts:268">
P2: JSON.parse without try-catch can throw on malformed thread metadata. Consider adding error handling.</violation>
</file>

<file name="deco-llm/server/tools/llm-with-thread.ts">

<violation number="1" location="deco-llm/server/tools/llm-with-thread.ts:148">
P1: Falsy check on `cost` will incorrectly throw an error when cost is 0 (a valid value for cached/free responses). Use explicit `undefined` or `null` checks instead.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

return p;
});
const response =
await env.MESH_REQUEST_CONTEXT?.state?.DATABASE.DATABASES_RUN_SQL({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Missing optional chaining on DATABASE. If state exists but DATABASE is undefined, accessing .DATABASES_RUN_SQL() will throw.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deco-llm/server/db/postgres.ts, line 28:

<comment>Missing optional chaining on `DATABASE`. If `state` exists but `DATABASE` is undefined, accessing `.DATABASES_RUN_SQL()` will throw.</comment>

<file context>
@@ -0,0 +1,33 @@
+    return p;
+  });
+  const response =
+    await env.MESH_REQUEST_CONTEXT?.state?.DATABASE.DATABASES_RUN_SQL({
+      sql,
+      params: sanitizedParams,
</file context>
Suggested change
await env.MESH_REQUEST_CONTEXT?.state?.DATABASE.DATABASES_RUN_SQL({
await env.MESH_REQUEST_CONTEXT?.state?.DATABASE?.DATABASES_RUN_SQL({

Comment on lines +148 to +150
if (
error instanceof Error &&
error.message.includes("not found")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Falsy check on cost will incorrectly throw an error when cost is 0 (a valid value for cached/free responses). Use explicit undefined or null checks instead.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deco-llm/server/tools/llm-with-thread.ts, line 148:

<comment>Falsy check on `cost` will incorrectly throw an error when cost is 0 (a valid value for cached/free responses). Use explicit `undefined` or `null` checks instead.</comment>

<file context>
@@ -0,0 +1,276 @@
+        threadMessages = threadData.messages;
+      } catch (error) {
+        // Thread doesn't exist - continue with empty array
+        if (
+          error instanceof Error &&
+          error.message.includes("not found")
</file context>
Suggested change
if (
error instanceof Error &&
error.message.includes("not found")
if (
usageReport?.providerMetadata?.openrouter?.usage?.cost === undefined ||
usageReport?.providerMetadata?.openrouter?.usage?.cost === null
) {


// Parse thread metadata
const threadMetadata = thread.metadata
? (JSON.parse(thread.metadata) as Record<string, unknown>)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: JSON.parse without try-catch can throw on malformed thread metadata. Consider adding error handling.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deco-llm/server/tools/threads.ts, line 268:

<comment>JSON.parse without try-catch can throw on malformed thread metadata. Consider adding error handling.</comment>

<file context>
@@ -0,0 +1,283 @@
+
+      // Parse thread metadata
+      const threadMetadata = thread.metadata
+        ? (JSON.parse(thread.metadata) as Record<string, unknown>)
+        : null;
+
</file context>

role: row.role,
content: row.content,
created_at: row.created_at,
metadata: row.metadata ? (JSON.parse(row.metadata) as Record<string, unknown>) : null,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: JSON.parse without try-catch can throw on malformed data. If stored JSON is corrupted, this will crash the request. Consider wrapping in try-catch with fallback to null or logging the error.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At deco-llm/server/tools/threads.ts, line 247:

<comment>JSON.parse without try-catch can throw on malformed data. If stored JSON is corrupted, this will crash the request. Consider wrapping in try-catch with fallback to null or logging the error.</comment>

<file context>
@@ -0,0 +1,283 @@
+        role: row.role,
+        content: row.content,
+        created_at: row.created_at,
+        metadata: row.metadata ? (JSON.parse(row.metadata) as Record<string, unknown>) : null,
+        tool_calls: row.tool_calls ? (JSON.parse(row.tool_calls) as unknown[]) : null,
+        tokens_used: row.tokens_used,
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants