tool call fail msg in stream

This commit is contained in:
marko-kraemer 2025-04-05 12:01:15 +01:00
parent d27b814c97
commit eea33e967c
8 changed files with 49 additions and 372 deletions

View File

@ -321,4 +321,8 @@ if __name__ == "__main__":
delete_result = await files_tool.delete_file(test_file_path) delete_result = await files_tool.delete_file(test_file_path)
print("Delete file result:", delete_result) print("Delete file result:", delete_result)
# Test read_file after delete (should fail)
read_deleted_result = await files_tool.read_file(test_file_path)
print("Read deleted file result:", read_deleted_result)
asyncio.run(test_files_tool()) asyncio.run(test_files_tool())

View File

@ -1,74 +0,0 @@
class ParticleSystem {
constructor() {
this.particles = [];
}
createParticle(x, y, color) {
return {
x: x,
y: y,
color: color,
velocity: {
x: (Math.random() - 0.5) * 3,
y: (Math.random() - 0.5) * 3
},
size: Math.random() * 3 + 2,
life: 1,
decay: 0.02
};
}
emit(x, y, count, color) {
for (let i = 0; i < count; i++) {
this.particles.push(this.createParticle(x, y, color));
}
}
update(ctx) {
for (let i = this.particles.length - 1; i >= 0; i--) {
const p = this.particles[i];
p.x += p.velocity.x;
p.y += p.velocity.y;
p.life -= p.decay;
if (p.life <= 0) {
this.particles.splice(i, 1);
continue;
}
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fillStyle = `${p.color}${Math.floor(p.life * 255).toString(16).padStart(2, '0')}`;
ctx.fill();
}
}
}
class Trail {
constructor(maxPoints = 10) {
this.points = [];
this.maxPoints = maxPoints;
}
addPoint(x, y) {
this.points.unshift({ x, y, alpha: 1 });
if (this.points.length > this.maxPoints) {
this.points.pop();
}
}
draw(ctx) {
ctx.save();
for (let i = this.points.length - 1; i >= 0; i--) {
const p = this.points[i];
p.alpha = i / this.points.length;
ctx.beginPath();
ctx.arc(p.x, p.y, 15 * p.alpha, 0, Math.PI * 2);
ctx.fillStyle = `rgba(0, 255, 255, ${p.alpha * 0.3})`;
ctx.fill();
}
ctx.restore();
}
}

View File

@ -1,11 +0,0 @@
// Sound effects manager
const Sounds = {
flap: new Audio('assets/sounds/flap.mp3'),
score: new Audio('assets/sounds/score.mp3'),
hit: new Audio('assets/sounds/hit.mp3'),
play: function(sound) {
this[sound].currentTime = 0;
this[sound].play().catch(err => console.log('Audio play failed:', err));
}
};

View File

@ -1,29 +0,0 @@
// Sprite loading and management
const Sprites = {
bird: new Image(),
pipeTop: new Image(),
pipeBottom: new Image(),
background: new Image(),
load: function() {
return new Promise((resolve) => {
let loadedImages = 0;
const totalImages = 4;
const checkLoaded = () => {
loadedImages++;
if (loadedImages === totalImages) resolve();
};
this.bird.onload = checkLoaded;
this.pipeTop.onload = checkLoaded;
this.pipeBottom.onload = checkLoaded;
this.background.onload = checkLoaded;
this.bird.src = 'assets/images/bird.png';
this.pipeTop.src = 'assets/images/pipe-top.png';
this.pipeBottom.src = 'assets/images/pipe-bottom.png';
this.background.src = 'assets/images/background.png';
});
}
};

View File

@ -1,46 +0,0 @@
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #111;
font-family: 'Press Start 2P', cursive;
overflow: hidden;
}
canvas {
border: 3px solid #0ff;
background: #070721;
box-shadow: 0 0 20px #0ff;
}
#game-over {
display: none;
position: absolute;
color: #0ff;
font-size: 24px;
text-align: center;
text-shadow: 0 0 10px #0ff;
background: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
border: 2px solid #0ff;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { box-shadow: 0 0 10px #0ff; }
50% { box-shadow: 0 0 20px #0ff, 0 0 30px #f0f; }
100% { box-shadow: 0 0 10px #0ff; }
}
.score {
position: absolute;
top: 20px;
color: #0ff;
text-shadow: 0 0 10px #0ff;
}
#current-score { left: 20px; }
#high-score { right: 20px; }

View File

@ -1,193 +0,0 @@
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gameOverDiv = document.getElementById('game-over');
// Game constants
const GRAVITY = 0.4;
const FLAP_SPEED = -7;
const PIPE_SPEED = 2;
const PIPE_GAP = 150;
// Initialize particle system and trail
const particles = new ParticleSystem();
const trail = new Trail();
// Game state
let bird = {
x: 50,
y: canvas.height / 2,
velocity: 0,
width: 30,
height: 30,
rotation: 0,
wingAngle: 0
};
let pipes = [];
let score = 0;
let gameRunning = false;
let frameCount = 0;
let highScore = localStorage.getItem('highScore') || 0;
// Neon colors for the bird
const birdColors = {
primary: '#0ff',
secondary: '#f0f',
glow: '#fff'
};
function drawNeonBird() {
ctx.save();
ctx.translate(bird.x, bird.y);
ctx.rotate(bird.rotation * Math.PI / 180);
// Draw trail
trail.draw(ctx);
// Draw wing
bird.wingAngle = Math.sin(frameCount * 0.3) * 30;
// Bird body glow
ctx.shadowBlur = 20;
ctx.shadowColor = birdColors.primary;
// Main body
ctx.beginPath();
ctx.ellipse(0, 0, bird.width/2, bird.height/2, 0, 0, Math.PI * 2);
ctx.fillStyle = birdColors.primary;
ctx.fill();
// Wing
ctx.save();
ctx.rotate(bird.wingAngle * Math.PI / 180);
ctx.beginPath();
ctx.ellipse(0, 0, bird.width/3, bird.height/4, 0, 0, Math.PI);
ctx.fillStyle = birdColors.secondary;
ctx.fill();
ctx.restore();
// Eye
ctx.shadowBlur = 10;
ctx.shadowColor = birdColors.glow;
ctx.beginPath();
ctx.arc(bird.width/4, -bird.height/6, 3, 0, Math.PI * 2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.restore();
}
function drawNeonPipe(pipe, isTop) {
ctx.save();
ctx.shadowBlur = 15;
ctx.shadowColor = '#0ff';
ctx.strokeStyle = '#0ff';
ctx.lineWidth = 2;
ctx.fillStyle = 'rgba(0, 255, 255, 0.1)';
if (isTop) {
ctx.fillRect(pipe.x, pipe.y, pipe.width, pipe.height);
ctx.strokeRect(pipe.x, pipe.y, pipe.width, pipe.height);
} else {
ctx.fillRect(pipe.x, pipe.y, pipe.width, pipe.height);
ctx.strokeRect(pipe.x, pipe.y, pipe.width, pipe.height);
}
ctx.restore();
}
// Update the original drawPipes function
function drawPipes() {
pipes.forEach((pipe, index) => {
drawNeonPipe(pipe, index % 2 === 0);
});
}
// Update the original handleClick function
function handleClick() {
if (!gameRunning) {
startGame();
} else {
bird.velocity = FLAP_SPEED;
bird.rotation = -45;
particles.emit(bird.x, bird.y, 5, birdColors.primary);
Sounds.play('flap');
}
}
// Update the original updateGame function
function updateGame() {
if (!gameRunning) return;
// Update bird
bird.velocity += GRAVITY;
bird.y += bird.velocity;
// Update trail
trail.addPoint(bird.x, bird.y);
// Update bird rotation
if (bird.velocity > 0) {
bird.rotation += 4;
bird.rotation = Math.min(90, bird.rotation);
}
// Generate particles while moving
if (frameCount % 3 === 0) {
particles.emit(bird.x - 10, bird.y, 1, birdColors.secondary);
}
// Rest of the updateGame function remains the same
[... existing updateGame code ...]
}
// Update the original animate function
function animate() {
if (!gameRunning) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw background with a gradient
const gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
gradient.addColorStop(0, '#000');
gradient.addColorStop(1, '#111');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid effect
drawGrid();
updateGame();
drawPipes();
particles.update(ctx);
drawNeonBird();
drawScore();
frameCount++;
requestAnimationFrame(animate);
}
// Add new grid effect
function drawGrid() {
ctx.strokeStyle = 'rgba(0, 255, 255, 0.1)';
ctx.lineWidth = 1;
const gridSize = 30;
const offset = frameCount % gridSize;
for (let x = -offset; x < canvas.width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
for (let y = -offset; y < canvas.height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
}
// Start the game
initGame();

View File

@ -3,19 +3,34 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flappy Bird Clone</title> <title>Flappy Bird Test</title>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet"> <style>
<link rel="stylesheet" href="assets/styles.css"> canvas {
border: 1px solid black;
}
</style>
</head> </head>
<body> <body>
<div id="game-over">
Game Over!<br>
Score: <span id="final-score">0</span><br>
Click to restart
</div>
<canvas id="gameCanvas" width="320" height="480"></canvas> <canvas id="gameCanvas" width="320" height="480"></canvas>
<script src="assets/sounds.js"></script> <script>
<script src="assets/sprites.js"></script> const canvas = document.getElementById('gameCanvas');
<script src="game.js"></script> const ctx = canvas.getContext('2d');
// Test bird
const bird = {
x: 50,
y: 200,
size: 20
};
// Draw test bird
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'red';
ctx.fillRect(bird.x, bird.y, bird.size, bird.size);
}
draw();
</script>
</body> </body>
</html> </html>

View File

@ -240,13 +240,11 @@ class ResponseProcessor:
# Get the result # Get the result
result = execution["task"].result() result = execution["task"].result()
tool_call = execution["tool_call"] tool_call = execution["tool_call"]
tool_index = execution.get("tool_index", -1)
# Store result for later database updates # Store result for later database updates
tool_results_buffer.append((tool_call, result)) tool_results_buffer.append((tool_call, result))
# Get the tool index
tool_index = execution.get("tool_index", -1)
# Yield tool status message first # Yield tool status message first
yield { yield {
"type": "tool_status", "type": "tool_status",
@ -269,6 +267,20 @@ class ResponseProcessor:
except Exception as e: except Exception as e:
logger.error(f"Error getting tool execution result: {str(e)}") logger.error(f"Error getting tool execution result: {str(e)}")
tool_call = execution["tool_call"]
tool_index = execution.get("tool_index", -1)
# Yield error status
yield {
"type": "tool_status",
"status": "error",
"name": tool_call["name"],
"message": f"Error executing tool: {str(e)}",
"tool_index": tool_index
}
# Mark for removal
completed_executions.append(i)
# Remove completed executions from pending list (in reverse to maintain indices) # Remove completed executions from pending list (in reverse to maintain indices)
for i in sorted(completed_executions, reverse=True): for i in sorted(completed_executions, reverse=True):
@ -288,13 +300,11 @@ class ResponseProcessor:
if execution["task"].done(): if execution["task"].done():
result = execution["task"].result() result = execution["task"].result()
tool_call = execution["tool_call"] tool_call = execution["tool_call"]
tool_index = execution.get("tool_index", -1)
# Store result for later # Store result for later
tool_results_buffer.append((tool_call, result)) tool_results_buffer.append((tool_call, result))
# Get the tool index
tool_index = execution.get("tool_index", -1)
# Yield tool status message first # Yield tool status message first
yield { yield {
"type": "tool_status", "type": "tool_status",
@ -315,11 +325,12 @@ class ResponseProcessor:
logger.error(f"Error processing remaining tool execution: {str(e)}") logger.error(f"Error processing remaining tool execution: {str(e)}")
# Yield error status for the tool # Yield error status for the tool
if "tool_call" in execution: if "tool_call" in execution:
tool_call = execution["tool_call"]
tool_index = execution.get("tool_index", -1) tool_index = execution.get("tool_index", -1)
yield { yield {
"type": "tool_status", "type": "tool_status",
"status": "error", "status": "error",
"name": execution["tool_call"].get("name", "unknown"), "name": tool_call.get("name", "unknown"),
"message": f"Error processing tool result: {str(e)}", "message": f"Error processing tool result: {str(e)}",
"tool_index": tool_index "tool_index": tool_index
} }