Skip to content

Conversation

KaiSoKei
Copy link


Summary
This pull request introduces a new feature allowing the project to be run as a standalone Node.js server,
completely independent of the Cloudflare stack.

  1. Feature: Standalone Node.js Server

To improve the development experience and remove the dependency on Cloudflare for local
testing, a new standalone server setup has been added.

Changes:

  • Dependencies: Added @hono/node-server and dotenv.
  • Local Cache: A file-based cache (.cache.json) has been implemented to replace the
    Cloudflare KV store for token management during local development.
  • Refactored App Initialization: The Hono application setup has been moved to a shared
    src/app.ts file, allowing both the Cloudflare entrypoint (src/index.ts) and the new
    Node.s server (src/local-server.ts) to use the same core application logic without
    duplication.
  • New Scripts:
    • npm run build:local: Compiles the TypeScript code for the Node.js environment.
    • npm run start:local: Starts the local server on http://localhost:3000.
  • Configuration: A .env file is now used for local environment variable configuration,
    with .dev.vars still available for Cloudflare development.
  1. Documentation

The README.md file has been updated with a new "Running Locally" section that provides
clear instructions on how to run both the original Cloudflare setup (npm run dev) and
the new standalone Node.js setup (npm run start:local).

…eters

I've applied a fix for the tool-calling regression.
 The problem was that a shallow filter was failing to remove the $schema field from nested
  parts of the tool's JSON schema, causing the Gemini API to reject the request.
 I've replaced it with a recursive filter that thoroughly cleans the entire tool definition
  before sending it to the API. This should resolve the invalid JSON payload error.
i forked my main repo with the fixed issue
@GewoonJaap
Copy link
Owner

Thanks for the PR, will test it out later today. Before I test, does this still work fine with cloudflare?

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces standalone Node.js server capability to remove the dependency on Cloudflare infrastructure for local development. The changes enable the project to run as either a Cloudflare Worker or a standard Node.js application.

Key changes:

  • Added file-based caching system to replace Cloudflare KV store for local development
  • Refactored application setup into a shared module for code reuse between Cloudflare and Node.js environments
  • Added new NPM scripts and dependencies for local Node.js server operation

Reviewed Changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/utils/file-cache.ts Implements file-based cache to replace Cloudflare KV store for local development
src/local-server.ts Creates Node.js server entry point using Hono's node adapter
src/index.ts Refactored to use shared app creation function
src/app.ts Extracted shared Hono application setup logic from index.ts
package.json Added dependencies and scripts for local Node.js development
README.md Added documentation for both Cloudflare and standalone Node.js development modes
.env.template Added environment variable template for local configuration

const cacheFilePath = path.join(process.cwd(), '.cache.json');

interface Cache {
[key: string]: any;
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

Using 'any' type defeats the purpose of TypeScript. Consider using 'unknown' or a more specific type union like 'string | number | boolean | object'.

Suggested change
[key: string]: any;
[key: string]: string | number | boolean | object | null;

Copilot uses AI. Check for mistakes.

return value;
}
}
return value;
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The return type 'any' should be avoided. Consider using generics like 'Promise' or 'Promise' for better type safety.

Suggested change
return value;
async get<T>(key: string, type?: 'json'): Promise<T | null> {
const cache = await readCache();
const value = cache[key] ?? null;
if (type === 'json' && typeof value === 'string') {
try {
return JSON.parse(value) as T;
} catch (e) {
// Ignore if not valid JSON
return value as T;
}
}
return value as T;

Copilot uses AI. Check for mistakes.

return value;
},

async put(key: string, value: any, options?: { expirationTtl?: number }): Promise<void> {
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

The 'value' parameter uses 'any' type. Consider using 'unknown' or a more specific type for better type safety.

Suggested change
async put(key: string, value: any, options?: { expirationTtl?: number }): Promise<void> {
async put(key: string, value: unknown, options?: { expirationTtl?: number }): Promise<void> {

Copilot uses AI. Check for mistakes.

config();

const localEnv: Partial<Env> = {
GEMINI_CLI_KV: fileCache as any, // Use file cache as KV store
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

Using 'as any' bypasses type checking. Consider creating a proper type interface that both the KV store and file cache implement, or use a more specific type assertion.

Suggested change
GEMINI_CLI_KV: fileCache as any, // Use file cache as KV store
// Define a minimal KVStore interface for type safety
interface KVStore {
get(key: string): Promise<any>;
set(key: string, value: any): Promise<void>;
delete(key: string): Promise<void>;
// Add other methods as needed
}
// Load environment variables from .env file
config();
const localEnv: Partial<Env> = {
GEMINI_CLI_KV: fileCache as KVStore, // Use file cache as KV store

Copilot uses AI. Check for mistakes.

cache[key] = value;
await writeCache(cache);
if (options?.expirationTtl) {
// console.log(`File cache does not support TTL. Key '${key}' will not expire.`);
Copy link
Preview

Copilot AI Aug 18, 2025

Choose a reason for hiding this comment

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

Commented-out console.log statements should be removed from production code. If this logging is needed for debugging, consider using a proper logging mechanism or removing it entirely.

Suggested change
// console.log(`File cache does not support TTL. Key '${key}' will not expire.`);

Copilot uses AI. Check for mistakes.

@KaiSoKei
Copy link
Author

i FIXED THE TYPE ERRORS

Thanks for the PR, will test it out later today. Before I test, does this still work fine with cloudflare?

YES IT SHOULD WORK ALL I DID WAS ADDING NEW ENTRY POINT AND THE LOCAL CACHE FILE AND UPDATED THE PACKAGE.JSON FILE TO INCLUDE THE NEW START:LOCAL/BUILD:LOCAL COMMANDS THAT POINT TO THE NEW ENTRY POINT
YESTERDAY I DIDNT RUN THE TESTS AND THATS IT FEW TYPE VIOLATIONS

@KaiSoKei
Copy link
Author

Thanks for the PR, will test it out later today. Before I test, does this still work fine with cloudflare?

THANKS FOR THIS AWESOME PROJECT I PLAN TO USE IT BUT I DONT USE CLOADFLARE I RUN MY OWN VPS ITS JUST FOR TESTING AND PERSONAL USE SO I DONT NEED ALL THE FANCY TECH STACK AND EDGE COMPUTING
THATS WHY I CHANGED IT A BIT TO RUN LOCALY

@GewoonJaap
Copy link
Owner

Ah good to know! Yeah I built this around Cloudflare as it is a free way to host this 24/7 so you can use the api everywhere. But I understand some people prefer a fully locally version aswell. Looks good! Can you fix the conflict? Prob just the yarn.lock as there were some dependency updates today. Then I will merge it

icnludes     
"@hono/node-server": "^1.18.2",
 "dotenv": "^17.2.1",
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