Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/henry.py
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
print("Henry testing v0.8.0")
print("Henry testing v0.8.0")
print("Henry testing v0.8.0")
print("Henry testing v0.8.0")
print("Henry testing v0.8.0")

creating a new draft PR
yet another draft PR
and another draft PR
and yet another draft PR
Comment on lines +7 to +10
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

SyntaxError: stray text lines — convert to code or comments.

Lines are not valid Python and will fail at import/execute.

Apply this minimal fix:

-creating a new draft PR 
-yet another draft PR 
-and another draft PR
-and yet another draft PR
+# creating a new draft PR
+# yet another draft PR
+# and another draft PR
+# and yet another draft PR
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
creating a new draft PR
yet another draft PR
and another draft PR
and yet another draft PR
# creating a new draft PR
# yet another draft PR
# and another draft PR
# and yet another draft PR
🧰 Tools
🪛 Ruff (0.12.2)

7-7: SyntaxError: Simple statements must be separated by newlines or semicolons


7-7: SyntaxError: Simple statements must be separated by newlines or semicolons


7-7: SyntaxError: Simple statements must be separated by newlines or semicolons


7-7: SyntaxError: Simple statements must be separated by newlines or semicolons


8-8: SyntaxError: Simple statements must be separated by newlines or semicolons


8-8: SyntaxError: Simple statements must be separated by newlines or semicolons


8-8: SyntaxError: Simple statements must be separated by newlines or semicolons


9-9: SyntaxError: Expected a statement


9-9: SyntaxError: Simple statements must be separated by newlines or semicolons


9-9: SyntaxError: Simple statements must be separated by newlines or semicolons


10-10: SyntaxError: Expected a statement


10-10: SyntaxError: Simple statements must be separated by newlines or semicolons


10-10: SyntaxError: Simple statements must be separated by newlines or semicolons


10-10: SyntaxError: Simple statements must be separated by newlines or semicolons

🤖 Prompt for AI Agents
In src/henry.py around lines 7 to 10 there are plain English lines ("creating a
new draft PR", "yet another draft PR", etc.) that are not valid Python and cause
a SyntaxError; convert those lines into valid code or comments — the minimal fix
is to prefix each line with # (or wrap them in a triple-quoted string if
intended as a block comment), save, and run a quick import to confirm the file
parses.

60 changes: 60 additions & 0 deletions src/llm/providers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require('dotenv').config()
const express = require('express')
const cors = require('cors')
const path = require('path')
const providers = require('./src/llm/providers')

const app = express()
const port = process.env.PORT || 3000

// Middleware
app.use(cors())
app.use(express.json())
app.use(express.static('public'))

// Get available providers and models
app.get('/api/providers', (req, res) => {
const providerInfo = Object.entries(providers).map(([id, provider]) => ({
id,
name: provider.name,
models: provider.models
}))
res.json(providerInfo)
})

// Generate article endpoint
app.post('/api/generate-article', async (req, res) => {
try {
const { topic, provider: providerId, model } = req.body

if (!topic) {
return res.status(400).json({ error: 'Topic is required' })
}

if (!providerId || !providers[providerId]) {
return res.status(400).json({ error: 'Invalid provider' })
}

if (!model || !providers[providerId].models.includes(model)) {
return res.status(400).json({ error: 'Invalid model for provider' })
}

const provider = providers[providerId]
const prompt = `Write a short, informative article about ${topic}. The article should be between 200-300 words.`

try {
const article = await provider.generate(provider.client, model, prompt)
res.json({ article, provider: provider.name, model })
} catch (error) {
console.error(`Error with ${provider.name}:`, error)
res.status(500).json({ error: `Failed to generate article using ${provider.name}` })
}
} catch (error) {
console.error('Error:', error)
res.status(500).json({ error: 'Failed to process request' })
}
})

app.listen(port, () => {
console.log(`Server running on port ${port}`)
})
Comment on lines +1 to +60
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Wrong language/file type: Node/Express code checked into a .py file.

This won’t run and will trip Python linters/CI. Also, it appears to start another Express server on port 3000, duplicating wanda/server.js and risking port conflicts.

Apply these steps:

  • Move this server to a JS/TS file (e.g., src/llm/server.js) and remove src/llm/providers.py.
  • Ensure the providers registry lives in a separate module (e.g., src/llm/providers/index.js) and import it with a relative path from the server (no self-require).
  • Pick a single server (merge with wanda/server.js) or use a distinct port to avoid conflicts.

Delete mistaken Python file:

- require('dotenv').config()
- const express = require('express')
- const cors = require('cors')
- const path = require('path')
- const providers = require('./src/llm/providers')
- ...
- app.listen(port, () => {
-   console.log(`Server running on port ${port}`)
- }) 
+ # (file removed; moved to JS)

New server file (outside current range) for clarity:

// src/llm/server.js
require('dotenv').config()
const express = require('express')
const cors = require('cors')
const providers = require('./providers') // e.g., src/llm/providers/index.js

const app = express()
const port = process.env.PORT || 3001 // avoid 3000 clash with wanda/server.js

app.use(cors())
app.use(express.json())

app.get('/api/providers', (req, res) => {
  const info = Object.entries(providers).map(([id, p]) => ({ id, name: p.name, models: p.models }))
  res.json(info)
})

app.post('/api/generate-article', async (req, res) => {
  const { topic, provider: providerId, model } = req.body
  if (typeof topic !== 'string' || topic.trim().length === 0 || topic.length > 512) {
    return res.status(400).json({ error: 'Topic is required' })
  }
  const p = providers[providerId]
  if (!p) return res.status(400).json({ error: 'Invalid provider' })
  if (!model || !p.models.includes(model)) return res.status(400).json({ error: 'Invalid model for provider' })
  try {
    const prompt = `Write a short, informative article about ${topic}. The article should be between 200-300 words.`
    const article = await p.generate(p.client, model, prompt)
    res.json({ article, provider: p.name, model })
  } catch (err) {
    console.error(`Error with ${p.name}:`, err)
    res.status(500).json({ error: `Failed to generate article using ${p.name}` })
  }
})

app.listen(port, () => console.log(`Server running on port ${port}`))

Unify both servers behind one Express app if possible to simplify deployment and routing.

🧰 Tools
🪛 Ruff (0.12.2)

2-2: SyntaxError: Simple statements must be separated by newlines or semicolons


3-3: SyntaxError: Simple statements must be separated by newlines or semicolons


4-4: SyntaxError: Simple statements must be separated by newlines or semicolons


5-5: SyntaxError: Simple statements must be separated by newlines or semicolons


7-7: SyntaxError: Simple statements must be separated by newlines or semicolons


8-8: SyntaxError: Simple statements must be separated by newlines or semicolons


8-8: SyntaxError: Expected an expression


10-10: SyntaxError: Expected a statement


15-15: SyntaxError: Expected a statement


15-15: SyntaxError: Simple statements must be separated by newlines or semicolons


15-15: SyntaxError: Simple statements must be separated by newlines or semicolons


16-16: SyntaxError: Expected a parameter name


16-16: SyntaxError: Expected an expression


17-17: SyntaxError: Expected ',', found name


17-17: SyntaxError: Expected ',', found '='


17-17: SyntaxError: Expected a parameter name


17-17: SyntaxError: Expected an expression


19-19: SyntaxError: Expected ',', found ':'


20-20: SyntaxError: Expected ',', found ':'


22-22: SyntaxError: Expected ',', found name


25-25: SyntaxError: Expected a statement


25-25: SyntaxError: Simple statements must be separated by newlines or semicolons


25-25: SyntaxError: Simple statements must be separated by newlines or semicolons


26-26: SyntaxError: Expected ')', found 'async'


26-26: SyntaxError: Expected 'def', 'with' or 'for' to follow 'async', found '('


26-26: SyntaxError: Expected an expression


27-27: SyntaxError: Expected an identifier, but found a keyword 'try' that cannot be used here


27-27: SyntaxError: Expected ',', found '{'


28-28: SyntaxError: Expected ',', found '{'


28-28: SyntaxError: Expected ',', found ':'


28-28: SyntaxError: Expected ',', found '='


30-30: SyntaxError: Expected an expression


30-30: SyntaxError: Expected ',', found ')'


31-31: SyntaxError: Expected an identifier, but found a keyword 'return' that cannot be used here


31-31: SyntaxError: Expected ',', found name


34-34: SyntaxError: Expected an expression


34-34: SyntaxError: Expected an expression


34-34: SyntaxError: Expected an expression


34-34: SyntaxError: Expected ',', found ')'


35-35: SyntaxError: Expected an identifier, but found a keyword 'return' that cannot be used here


35-35: SyntaxError: Expected ',', found name


38-38: SyntaxError: Expected an expression


38-38: SyntaxError: Expected an expression


38-38: SyntaxError: Expected an expression


38-38: SyntaxError: Expected ',', found ')'


39-39: SyntaxError: Expected an identifier, but found a keyword 'return' that cannot be used here


39-39: SyntaxError: Expected ',', found name


42-42: SyntaxError: Expected ',', found name


42-42: SyntaxError: Expected ',', found name


42-42: SyntaxError: Expected ',', found '='


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found '='


43-43: SyntaxError: Got unexpected token `


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Got unexpected token $


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Expected ',', found int


43-43: SyntaxError: Expected ',', found name


43-43: SyntaxError: Got unexpected token `


43-44: SyntaxError: Expected '}', found NonLogicalNewline


45-45: SyntaxError: Unexpected indentation


45-45: SyntaxError: Expected ':', found '{'


46-46: SyntaxError: Expected ',', found name


46-46: SyntaxError: Expected ',', found '='


47-47: SyntaxError: Expected ',', found name


47-47: SyntaxError: Expected ',', found ':'


48-48: SyntaxError: Simple statements must be separated by newlines or semicolons


48-48: SyntaxError: Simple statements must be separated by newlines or semicolons


49-49: SyntaxError: Got unexpected token `


49-49: SyntaxError: Expected ')', found 'with'


49-49: SyntaxError: Got unexpected token $


49-49: SyntaxError: Invalid annotated assignment target


49-49: SyntaxError: Got unexpected token `


49-49: SyntaxError: Expected a statement


49-49: SyntaxError: Expected a statement


49-50: SyntaxError: Expected a statement


50-50: SyntaxError: Unexpected indentation


50-50: SyntaxError: Got unexpected token `


50-50: SyntaxError: Expected ':', found name


50-50: SyntaxError: Expected ',', found name


50-50: SyntaxError: Expected ':', found name


50-50: SyntaxError: Expected ',', found name


50-50: SyntaxError: Got unexpected token $


50-50: SyntaxError: Got unexpected token `


51-51: SyntaxError: Expected a statement


51-52: SyntaxError: Expected a statement


52-52: SyntaxError: unindent does not match any outer indentation level


52-52: SyntaxError: Expected a statement


52-52: SyntaxError: Simple statements must be separated by newlines or semicolons


54-54: SyntaxError: Expected ',', found name


56-56: SyntaxError: Expected a statement


56-56: SyntaxError: Expected a statement


56-57: SyntaxError: Expected a statement


58-58: SyntaxError: Expected a parameter name


58-58: SyntaxError: Expected an expression


59-59: SyntaxError: Got unexpected token `


59-59: SyntaxError: Expected ',', found name


59-59: SyntaxError: Expected ',', found name


59-59: SyntaxError: Expected ',', found name


59-59: SyntaxError: Got unexpected token $


59-59: SyntaxError: Got unexpected token `

🤖 Prompt for AI Agents
In src/llm/providers.py (lines 1-60) the file contains a Node/Express server
mistakenly checked in as a .py file and starts an Express app that may conflict
with wanda/server.js; delete src/llm/providers.py, create a JS module for the
providers registry at src/llm/providers/index.js (export an object keyed by
provider id with name, models, client, generate), move the Express server code
into src/llm/server.js and import the providers with a relative path
(require('./providers')), remove any duplicated server startup from the
providers module, and either merge this server into wanda/server.js or change
the port (e.g., use process.env.PORT || 3001) and update package.json scripts to
run the new server; ensure all imports/exports use correct JS module syntax and
no self-require from the same file.

54 changes: 54 additions & 0 deletions wanda/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
require('dotenv').config()
const express = require('express')
const cors = require('cors')
const OpenAI = require('openai')

const app = express()
const port = process.env.PORT || 3000

// Initialize OpenAI client
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
})
Comment on lines +10 to +12
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add client reliability controls and early API key validation.

Configure OpenAI SDK timeouts/retries and fail fast if OPENAI_API_KEY is missing. The SDK supports maxRetries and timeout on the client. (github.com)

-const openai = new OpenAI({
-  apiKey: process.env.OPENAI_API_KEY
-})
+if (!process.env.OPENAI_API_KEY) {
+  throw new Error('OPENAI_API_KEY is not set')
+}
+const openai = new OpenAI({
+  apiKey: process.env.OPENAI_API_KEY,
+  timeout: 20_000,   // 20s
+  maxRetries: 2      // SDK default is 2; set explicitly
+})
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY
})
if (!process.env.OPENAI_API_KEY) {
throw new Error('OPENAI_API_KEY is not set')
}
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
timeout: 20_000, // 20s
maxRetries: 2 // SDK default is 2; set explicitly
})
🤖 Prompt for AI Agents
In wanda/server.js around lines 10 to 12, the OpenAI client is created without
API-key validation or reliability settings; add an early check that
process.env.OPENAI_API_KEY exists and exit with a clear error if missing, and
instantiate OpenAI with client reliability options (set timeout in ms and
maxRetries) to avoid hanging and auto-retry behavior; choose sensible defaults
(e.g., timeout 30_000 and maxRetries 2–3) and ensure the env value is passed
securely to the client configuration.


// Middleware
app.use(cors())
app.use(express.json())
app.use(express.static('public'))

// Generate article endpoint
app.post('/api/generate-article', async (req, res) => {
try {
const { topic } = req.body

if (!topic) {
return res.status(400).json({ error: 'Topic is required' })
}
Comment on lines +24 to +26
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Harden input validation.

Validate string type, trim, and length to avoid abuse and excessive prompt sizes.

-    if (!topic) {
+    if (typeof topic !== 'string' || topic.trim().length === 0 || topic.length > 512) {
       return res.status(400).json({ error: 'Topic is required' })
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!topic) {
return res.status(400).json({ error: 'Topic is required' })
}
if (typeof topic !== 'string' || topic.trim().length === 0 || topic.length > 512) {
return res.status(400).json({ error: 'Topic is required' })
}
🤖 Prompt for AI Agents
In wanda/server.js around lines 24 to 26, the current check only ensures topic
exists but doesn't validate type, trimming, or length; update the validation to
ensure topic is a string, trim whitespace, reject empty strings after trim, and
enforce a maximum safe length (e.g., 1000 characters) to prevent abuse or
excessively large prompts; if validation fails return res.status(400).json with
a clear error message indicating which check failed.


const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "You are a helpful assistant that generates short, informative articles."
},
{
role: "user",
content: `Write a short, informative article about ${topic}. The article should be between 200-300 words.`
Comment on lines +22 to +37

Choose a reason for hiding this comment

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

security: topic from req.body is directly interpolated into the OpenAI prompt without sanitization, enabling prompt injection attacks that can manipulate model output or leak sensitive information.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In wanda/server.js, lines 22-37, the `topic` value from `req.body` is directly interpolated into the OpenAI prompt, making the endpoint vulnerable to prompt injection attacks. Please sanitize the `topic` input to remove newlines and special characters before using it in the prompt. Replace the direct usage of `topic` with a sanitized version to prevent prompt injection.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const { topic } = req.body
if (!topic) {
return res.status(400).json({ error: 'Topic is required' })
}
const completion = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "You are a helpful assistant that generates short, informative articles."
},
{
role: "user",
content: `Write a short, informative article about ${topic}. The article should be between 200-300 words.`
const { topic } = req.body
// Basic sanitization to prevent prompt injection
const sanitizedTopic = typeof topic === 'string' ? topic.replace(/[\r\n\[\]{}<>]/g, '') : '';
...
content: `Write a short, informative article about ${sanitizedTopic}. The article should be between 200-300 words.`

}
],
temperature: 0.7,
max_tokens: 500
})

const article = completion.choices[0].message.content
res.json({ article })
Comment on lines +44 to +45

Choose a reason for hiding this comment

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

correctness: completion.choices[0].message.content may throw if choices is empty or message/content is missing, causing a runtime crash for unexpected OpenAI API responses.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In wanda/server.js, lines 44-45, the code assumes that `completion.choices[0].message.content` always exists, but if the OpenAI API returns an unexpected response (e.g., empty choices), this will cause a runtime crash. Add a check to ensure `choices`, `choices[0]`, `message`, and `content` exist before accessing them. If not, return a 502 error with an appropriate message.
📝 Committable Code Suggestion

‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
const article = completion.choices[0].message.content
res.json({ article })
if (!completion.choices || !completion.choices[0] || !completion.choices[0].message || !completion.choices[0].message.content) {
return res.status(502).json({ error: 'Invalid response from OpenAI API' })
}
const article = completion.choices[0].message.content
res.json({ article })

} catch (error) {
console.error('Error:', error)
res.status(500).json({ error: 'Failed to generate article' })
}
})

app.listen(port, () => {
console.log(`Server running on port ${port}`)
})