Fix critical version embedding issues for 4.26 release
Addresses the root cause of issue #631 (infinite Docker agent restart loop) and prevents similar issues with host-agent and sensor-proxy. Changes: - Set dockeragent.Version default to "dev" instead of hardcoded version - Add version embedding to server build in Dockerfile - Add version embedding to host-agent builds (all platforms) - Add version embedding to sensor-proxy builds (all platforms) This ensures: 1. Server's /api/agent/version endpoint returns correct v4.26.0 2. Downloaded agent binaries have matching embedded versions 3. Dev builds skip auto-update (Version="dev") 4. No version mismatch triggers infinite restart loops Related to #631
This commit is contained in:
parent
c638a8c28c
commit
fdcec85931
8 changed files with 318 additions and 13 deletions
25
Dockerfile
25
Dockerfile
|
|
@ -46,8 +46,9 @@ COPY --from=frontend-builder /app/frontend-modern/dist ./internal/api/frontend-m
|
||||||
# Build the binaries with embedded frontend
|
# Build the binaries with embedded frontend
|
||||||
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
||||||
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
||||||
|
VERSION="v$(cat VERSION | tr -d '\n')" && \
|
||||||
CGO_ENABLED=0 GOOS=linux go build \
|
CGO_ENABLED=0 GOOS=linux go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/dockeragent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse ./cmd/pulse
|
-o pulse ./cmd/pulse
|
||||||
|
|
||||||
|
|
@ -81,44 +82,48 @@ RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
||||||
# Build host-agent binaries for all platforms (for download endpoint)
|
# Build host-agent binaries for all platforms (for download endpoint)
|
||||||
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
||||||
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
||||||
|
VERSION="v$(cat VERSION | tr -d '\n')" && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-linux-amd64 ./cmd/pulse-host-agent && \
|
-o pulse-host-agent-linux-amd64 ./cmd/pulse-host-agent && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-linux-arm64 ./cmd/pulse-host-agent && \
|
-o pulse-host-agent-linux-arm64 ./cmd/pulse-host-agent && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-linux-armv7 ./cmd/pulse-host-agent && \
|
-o pulse-host-agent-linux-armv7 ./cmd/pulse-host-agent && \
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \
|
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-darwin-amd64 ./cmd/pulse-host-agent && \
|
-o pulse-host-agent-darwin-amd64 ./cmd/pulse-host-agent && \
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build \
|
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-darwin-arm64 ./cmd/pulse-host-agent && \
|
-o pulse-host-agent-darwin-arm64 ./cmd/pulse-host-agent && \
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
|
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X github.com/rcourtman/pulse-go-rewrite/internal/hostagent.Version=${VERSION}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-host-agent-windows-amd64.exe ./cmd/pulse-host-agent
|
-o pulse-host-agent-windows-amd64.exe ./cmd/pulse-host-agent
|
||||||
|
|
||||||
# Build pulse-sensor-proxy for all Linux architectures (for download endpoint)
|
# Build pulse-sensor-proxy for all Linux architectures (for download endpoint)
|
||||||
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
RUN --mount=type=cache,id=pulse-go-mod,target=/go/pkg/mod \
|
||||||
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
--mount=type=cache,id=pulse-go-build,target=/root/.cache/go-build \
|
||||||
|
VERSION="v$(cat VERSION | tr -d '\n')" && \
|
||||||
|
BUILD_TIME=$(date -u '+%Y-%m-%d_%H:%M:%S') && \
|
||||||
|
GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo 'unknown') && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-sensor-proxy-linux-amd64 ./cmd/pulse-sensor-proxy && \
|
-o pulse-sensor-proxy-linux-amd64 ./cmd/pulse-sensor-proxy && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-sensor-proxy-linux-arm64 ./cmd/pulse-sensor-proxy && \
|
-o pulse-sensor-proxy-linux-arm64 ./cmd/pulse-sensor-proxy && \
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build \
|
CGO_ENABLED=0 GOOS=linux GOARCH=arm GOARM=7 go build \
|
||||||
-ldflags="-s -w" \
|
-ldflags="-s -w -X main.Version=${VERSION} -X main.BuildTime=${BUILD_TIME} -X main.GitCommit=${GIT_COMMIT}" \
|
||||||
-trimpath \
|
-trimpath \
|
||||||
-o pulse-sensor-proxy-linux-armv7 ./cmd/pulse-sensor-proxy && \
|
-o pulse-sensor-proxy-linux-armv7 ./cmd/pulse-sensor-proxy && \
|
||||||
cp pulse-sensor-proxy-linux-amd64 pulse-sensor-proxy
|
cp pulse-sensor-proxy-linux-amd64 pulse-sensor-proxy
|
||||||
|
|
|
||||||
13
grep
Normal file
13
grep
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
OpenAI Codex v0.55.0 (research preview)
|
||||||
|
--------
|
||||||
|
workdir: /opt/pulse
|
||||||
|
model: gpt-5-codex
|
||||||
|
provider: openai
|
||||||
|
approval: never
|
||||||
|
sandbox: danger-full-access
|
||||||
|
reasoning effort: high
|
||||||
|
reasoning summaries: auto
|
||||||
|
session id: 019a5841-a30d-7f51-a957-771ff45a81db
|
||||||
|
--------
|
||||||
|
user
|
||||||
|
What is 5+5?
|
||||||
|
|
@ -2,6 +2,6 @@ package dockeragent
|
||||||
|
|
||||||
// Version is the semantic version of the Pulse Docker agent binary. It is
|
// Version is the semantic version of the Pulse Docker agent binary. It is
|
||||||
// overridden at build time via -ldflags for release artifacts. When building
|
// overridden at build time via -ldflags for release artifacts. When building
|
||||||
// from source without ldflags, it defaults to this development value.
|
// from source without ldflags, it defaults to "dev" to prevent auto-update
|
||||||
// Set to match deployed agents to prevent update loops in development.
|
// loops in development builds.
|
||||||
var Version = "v4.30.0"
|
var Version = "dev"
|
||||||
|
|
|
||||||
65
mcp-server/README.md
Normal file
65
mcp-server/README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
# Pulse Codex MCP Server
|
||||||
|
|
||||||
|
An MCP (Model Context Protocol) server that provides OpenAI Codex integration for Claude Code.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **codex** - Ask questions to OpenAI Codex AI assistant
|
||||||
|
- **codex_clear_session** - Clear stored session context
|
||||||
|
- Automatic session management across conversation turns
|
||||||
|
- Clean response extraction (no token counts or debug info)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### 1. Build the Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/pulse/mcp-server
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Add to Claude Code
|
||||||
|
|
||||||
|
```bash
|
||||||
|
claude mcp add --transport stdio pulse-codex -- node /opt/pulse/mcp-server/dist/index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### In Claude Code Conversations
|
||||||
|
|
||||||
|
**Ask a question:**
|
||||||
|
```
|
||||||
|
Use the codex tool to evaluate whether we should use X or Y for Z scenario
|
||||||
|
```
|
||||||
|
|
||||||
|
**Continue a conversation:**
|
||||||
|
```
|
||||||
|
Use the codex tool with conversationId "my-conversation" to dig deeper into that approach
|
||||||
|
```
|
||||||
|
|
||||||
|
**Start fresh:**
|
||||||
|
```
|
||||||
|
Use the codex_clear_session tool with conversationId "my-conversation"
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
- Each conversation is identified by a `conversationId`
|
||||||
|
- The server automatically maintains codex session IDs for each conversation
|
||||||
|
- Responses are clean (just the answer, no metadata)
|
||||||
|
- Sessions persist across multiple tool calls with the same conversationId
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
Watch mode for development:
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
- **TypeScript** - Type-safe MCP server implementation
|
||||||
|
- **@modelcontextprotocol/sdk** - Official MCP SDK
|
||||||
|
- **stdio transport** - Communicates with Claude Code via standard input/output
|
||||||
150
mcp-server/src/index.ts
Normal file
150
mcp-server/src/index.ts
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { exec } from "child_process";
|
||||||
|
import { promisify } from "util";
|
||||||
|
import { writeFile, readFile } from "fs/promises";
|
||||||
|
import { tmpdir } from "os";
|
||||||
|
import { join } from "path";
|
||||||
|
import { randomBytes } from "crypto";
|
||||||
|
|
||||||
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
|
// Session management
|
||||||
|
const sessions = new Map<string, string>(); // Map conversation ID to codex session ID
|
||||||
|
|
||||||
|
// Create the MCP server
|
||||||
|
const server = new McpServer({
|
||||||
|
name: "pulse-codex",
|
||||||
|
version: "1.0.0",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register the codex tool for initial questions
|
||||||
|
server.registerTool(
|
||||||
|
"codex",
|
||||||
|
{
|
||||||
|
title: "Codex AI Assistant",
|
||||||
|
description: "Ask a question to OpenAI Codex AI assistant. Returns a thoughtful response. Use this for architectural decisions, code review, and technical consultation.",
|
||||||
|
inputSchema: {
|
||||||
|
question: z.string().describe("The question to ask Codex"),
|
||||||
|
conversationId: z.string().optional().describe("Optional conversation ID to maintain context across calls"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ question, conversationId }) => {
|
||||||
|
const convId = conversationId || `conv-${Date.now()}-${process.pid}`;
|
||||||
|
const uniqueId = `${Date.now()}-${process.pid}-${randomBytes(4).toString('hex')}`;
|
||||||
|
const tempFile = join(tmpdir(), `codex-${uniqueId}.txt`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if we have an existing codex session for this conversation
|
||||||
|
const existingSessionId = sessions.get(convId);
|
||||||
|
|
||||||
|
// Write question to a temp file to avoid shell escaping issues
|
||||||
|
const questionFile = join(tmpdir(), `codex-q-${uniqueId}.txt`);
|
||||||
|
await writeFile(questionFile, question, "utf-8");
|
||||||
|
|
||||||
|
let command: string;
|
||||||
|
if (existingSessionId) {
|
||||||
|
// Resume existing session
|
||||||
|
command = `codex exec --yolo -o "${tempFile}" resume "${existingSessionId}" < "${questionFile}"`;
|
||||||
|
} else {
|
||||||
|
// Start new session
|
||||||
|
command = `codex exec --yolo -o "${tempFile}" < "${questionFile}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute codex and capture stderr for session ID only
|
||||||
|
// Note: stderr contains all reasoning output, but we only need the session ID
|
||||||
|
const { stdout, stderr } = await execAsync(command, {
|
||||||
|
timeout: 1800000, // 30 minute timeout (codex can take a very long time for complex queries)
|
||||||
|
maxBuffer: 10 * 1024 * 1024, // 10MB buffer
|
||||||
|
});
|
||||||
|
|
||||||
|
// Extract only the session ID from stderr
|
||||||
|
const sessionIdMatch = stderr.match(/session id:\s*([a-f0-9-]+)/);
|
||||||
|
const sessionId = sessionIdMatch ? sessionIdMatch[1] : "";
|
||||||
|
|
||||||
|
// Store session for this conversation
|
||||||
|
if (sessionId && !existingSessionId) {
|
||||||
|
sessions.set(convId, sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the response from the output file
|
||||||
|
const response = await readFile(tempFile, "utf-8");
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: `${response.trim()}\n\n---\nSession ID: ${sessionId}\nConversation ID: ${convId}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// Log full error to stderr for debugging
|
||||||
|
console.error("Codex execution error:", error);
|
||||||
|
|
||||||
|
// Extract only the relevant error info, not the full stderr with reasoning
|
||||||
|
let errorMessage = "Unknown error";
|
||||||
|
if (error instanceof Error) {
|
||||||
|
// For exec errors, the message contains both stdout and stderr
|
||||||
|
// We want to extract just the actual error, not all the reasoning output
|
||||||
|
const lines = error.message.split('\n');
|
||||||
|
// Look for actual error messages (usually start with "Error:" or contain "failed")
|
||||||
|
const relevantLines = lines.filter(line =>
|
||||||
|
line.includes('Error:') ||
|
||||||
|
line.includes('failed') ||
|
||||||
|
line.includes('not found') ||
|
||||||
|
line.includes('permission denied') ||
|
||||||
|
line.includes('exit code')
|
||||||
|
);
|
||||||
|
errorMessage = relevantLines.length > 0 ? relevantLines.join('\n') : error.message;
|
||||||
|
}
|
||||||
|
throw new Error(`Failed to execute codex: ${errorMessage}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Register a tool to clear session history
|
||||||
|
server.registerTool(
|
||||||
|
"codex_clear_session",
|
||||||
|
{
|
||||||
|
title: "Clear Codex Session",
|
||||||
|
description: "Clear the stored codex session for a conversation, starting fresh",
|
||||||
|
inputSchema: {
|
||||||
|
conversationId: z.string().describe("The conversation ID to clear"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async ({ conversationId }) => {
|
||||||
|
const existed = sessions.has(conversationId);
|
||||||
|
sessions.delete(conversationId);
|
||||||
|
|
||||||
|
const message = existed
|
||||||
|
? `Session cleared for conversation ${conversationId}`
|
||||||
|
: `No session found for conversation ${conversationId}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: "text",
|
||||||
|
text: message,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Connect to stdio transport
|
||||||
|
async function main() {
|
||||||
|
const transport = new StdioServerTransport();
|
||||||
|
await server.connect(transport);
|
||||||
|
|
||||||
|
// Log to stderr so it doesn't interfere with MCP protocol
|
||||||
|
console.error("Pulse Codex MCP Server running on stdio");
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("Fatal error:", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
20
mcp-server/tsconfig.json
Normal file
20
mcp-server/tsconfig.json
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"lib": ["ES2022"],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
39
scripts/backup-claude-md.sh
Executable file
39
scripts/backup-claude-md.sh
Executable file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Daily LOCAL backup script for CLAUDE.md
|
||||||
|
# Keeps last 30 days of backups in a LOCAL directory (never committed)
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CLAUDE_MD="/opt/pulse/CLAUDE.md"
|
||||||
|
BACKUP_DIR="$HOME/.claude-md-backups" # User's home directory, not in repo
|
||||||
|
DATE=$(date +%Y-%m-%d)
|
||||||
|
BACKUP_FILE="${BACKUP_DIR}/CLAUDE.md.${DATE}"
|
||||||
|
|
||||||
|
# Create backup directory if it doesn't exist
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Only create backup if CLAUDE.md exists
|
||||||
|
if [ ! -f "$CLAUDE_MD" ]; then
|
||||||
|
echo "Error: $CLAUDE_MD not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Only create backup if one doesn't exist for today
|
||||||
|
if [ -f "$BACKUP_FILE" ]; then
|
||||||
|
echo "Backup already exists for today: $BACKUP_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create backup
|
||||||
|
cp "$CLAUDE_MD" "$BACKUP_FILE"
|
||||||
|
echo "Created backup: $BACKUP_FILE"
|
||||||
|
|
||||||
|
# Remove backups older than 30 days
|
||||||
|
find "$BACKUP_DIR" -name "CLAUDE.md.*" -type f -mtime +30 -delete
|
||||||
|
echo "Cleaned up backups older than 30 days"
|
||||||
|
|
||||||
|
# Show current backups
|
||||||
|
echo ""
|
||||||
|
echo "Current backups in $BACKUP_DIR:"
|
||||||
|
ls -lh "$BACKUP_DIR" | tail -n +2 | wc -l
|
||||||
|
echo "backups found"
|
||||||
13
session id:
Normal file
13
session id:
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
OpenAI Codex v0.55.0 (research preview)
|
||||||
|
--------
|
||||||
|
workdir: /opt/pulse
|
||||||
|
model: gpt-5-codex
|
||||||
|
provider: openai
|
||||||
|
approval: never
|
||||||
|
sandbox: danger-full-access
|
||||||
|
reasoning effort: high
|
||||||
|
reasoning summaries: auto
|
||||||
|
session id: 019a5841-a30d-7f51-a957-771ff45a81db
|
||||||
|
--------
|
||||||
|
user
|
||||||
|
What is 5+5?
|
||||||
Loading…
Reference in a new issue