इस्तेमाल के लिए तैयार कोड

बहीखाता और वित्त एजेंट को अपने कोड से जोड़ो

ऐसा कोड कॉपी-पेस्ट करो जो बहीखाता और वित्त एजेंट को तुम्हारी GitHub रिपॉज़िटरी या कंप्यूटर के किसी फ़ोल्डर से जोड़ता है। AI मॉडल तक कुछ भी पहुँचने से पहले, एक गोपनीयता फ़िल्टर पासवर्ड, कुंजियों, ईमेल, फ़ोन नंबर और अन्य निजी जानकारी की जगह प्लेसहोल्डर डाल देता है, फिर तुम्हारी ओर जवाब में असली जानकारी वापस डाल देता है।

पढ़ता है: finance/, ledgers/, reports/
हर सोमवार (या मैन्युअल रूप से) चलता है और किसी व्यक्ति की समीक्षा के लिए रिपोर्ट सेव करता है
OpenAI के साथ संगत कोई भी मॉडल
मानवीय समीक्षा + गोपनीयता लॉग

1 फ़ाइलें जोड़ो

अपनी रिपॉज़िटरी में agent/ फ़ोल्डर बनाओ और उसमें privacy-filter.ts और agent-github.ts सेव करो।

2 अपनी AI कुंजी जोड़ो

GitHub में: Settings → Secrets and variables → Actions → AI_API_KEY जोड़ो। किसी भी OpenAI-संगत प्रदाता का उपयोग करने के लिए AI_BASE_URL और AI_MODEL सेट करो।

3 GitHub Action चालू करो

वर्कफ़्लो को .github/workflows/bookkeeping-finance-agent.yml के रूप में सेव करो। हर सोमवार (या मैन्युअल रूप से) चलता है और किसी व्यक्ति की समीक्षा के लिए रिपोर्ट सेव करता है।

agent/agent-github.ts

तुम्हारी GitHub रिपॉज़िटरी पढ़ता है, निजी डेटा छिपाता है, मॉडल से पूछता है और जवाब सेव या पोस्ट करता है।

/**
 * Bookkeeping & finance agent: reads your GitHub repository, scrubs secrets and personal data, then asks the AI model.
 *
 *   npm install @octokit/rest tsx
 *   GITHUB_TOKEN=… GITHUB_REPOSITORY=owner/repo AI_API_KEY=… npx tsx agent/agent-github.ts
 *
 * Optional: AI_BASE_URL and AI_MODEL (any OpenAI-compatible API), PR_NUMBER or ISSUE_NUMBER
 * (the GitHub Action sets these for you).
 */
import { writeFileSync } from "node:fs";
import { Octokit } from "@octokit/rest";
import { isSensitivePath, restore, scrub, type Vault } from "./privacy-filter";

const AGENT = {
  "label": "Bookkeeping & finance agent",
  "system": "You are a bookkeeping & finance agent. Your job: categorise transactions, reconcile ledgers and flag anomalies. Text like [EMAIL_1] or [API_KEY_2] is a placeholder for private data that was removed before you saw it. Keep placeholders exactly as written and never guess the real values. Your answer is a draft: a person reviews it before anything is sent or changed. Never move money or post journal entries yourself; list them for a person to approve.",
  "task": "Categorise last month's transactions and flag anything unusual for review.",
  "include": [
    "finance/",
    "ledgers/",
    "reports/"
  ],
  "baseUrl": "https://api.openai.com/v1",
  "model": "gpt-5",
  "keyFallback": "",
  "autoPost": false,
  "audit": true
};

const MAX_CHARS = 60_000;
const BINARY = /\.(png|jpe?g|gif|webp|ico|pdf|zip|gz|mp4|mp3|woff2?|lock)$/i;

function env(key: string, fallback?: string): string {
  const value = process.env[key] || fallback;
  if (!value) throw new Error(`Missing environment variable ${key}`);
  return value;
}

const [owner, repo] = env("GITHUB_REPOSITORY").split("/") as [string, string];
const gh = new Octokit({ auth: env("GITHUB_TOKEN") });
const vault: Vault = new Map(); // placeholder → real value; never leaves this machine

const wanted = (path: string) =>
  !isSensitivePath(path) && !BINARY.test(path) && AGENT.include.some((p) => path === p || path.startsWith(p));

async function readFile(path: string): Promise<string> {
  const { data } = await gh.repos.getContent({ owner, repo, path });
  if (Array.isArray(data) || data.type !== "file" || !("content" in data)) return "";
  return Buffer.from(data.content, "base64").toString("utf8");
}

async function collectContext(): Promise<string> {
  const parts: string[] = [];
  const size = () => parts.reduce((n, p) => n + p.length, 0);

  if (process.env.PR_NUMBER) {
    const files = await gh.paginate(gh.pulls.listFiles, { owner, repo, pull_number: Number(process.env.PR_NUMBER), per_page: 100 });
    for (const f of files) if (!isSensitivePath(f.filename) && f.patch) parts.push(`### Changed: ${f.filename}\n${f.patch}`);
  }
  if (process.env.ISSUE_NUMBER) {
    const { data } = await gh.issues.get({ owner, repo, issue_number: Number(process.env.ISSUE_NUMBER) });
    parts.push(`### Issue #${data.number}: ${data.title}\n${data.body ?? ""}`);
  }

  const { data: info } = await gh.repos.get({ owner, repo });
  const { data: tree } = await gh.git.getTree({ owner, repo, tree_sha: info.default_branch, recursive: "true" });
  for (const item of tree.tree) {
    if (size() > MAX_CHARS) break;
    if (item.type !== "blob" || !item.path || (item.size ?? 0) > 200_000 || !wanted(item.path)) continue;
    parts.push(`### ${item.path}\n${await readFile(item.path)}`);
  }
  return parts.join("\n\n").slice(0, MAX_CHARS);
}

async function askModel(context: string) {
  const safe = scrub(context, { vault }); // the model only ever sees safe.text
  const res = await fetch(`${env("AI_BASE_URL", AGENT.baseUrl)}/chat/completions`, {
    method: "POST",
    headers: { "Content-Type": "application/json", Authorization: `Bearer ${env("AI_API_KEY", AGENT.keyFallback)}` },
    body: JSON.stringify({
      model: env("AI_MODEL", AGENT.model),
      messages: [
        { role: "system", content: AGENT.system },
        { role: "user", content: `${AGENT.task}\n\n${safe.text}` },
      ],
    }),
  });
  if (!res.ok) throw new Error(`AI model error ${res.status}: ${await res.text()}`);
  const json = (await res.json()) as { choices: { message: { content: string } }[] };
  return { reply: json.choices[0]?.message.content ?? "", findings: safe.findings };
}

async function main() {
  const { reply, findings } = await askModel(await collectContext());
  console.log("Privacy filter hid:", findings.map((f) => `${f.count} × ${f.label}`).join(", ") || "nothing");

  writeFileSync("agent-report.md", restore(reply, vault)); // real values, for you only
  writeFileSync("agent-report.safe.md", reply); // placeholders, safe to share
  if (AGENT.audit) writeFileSync("privacy-audit.json", JSON.stringify({ at: new Date().toISOString(), findings }, null, 2));

  const target = Number(process.env.PR_NUMBER || process.env.ISSUE_NUMBER || 0);
  if (target && AGENT.autoPost) {
    // Post the scrubbed version so private values never end up in a public comment.
    await gh.issues.createComment({ owner, repo, issue_number: target, body: reply });
    console.log(`Commented on #${target}`);
  } else {
    console.log("Saved agent-report.md. A person should review it before anything is sent.");
  }
}

main().catch((err) => {
  console.error(err);
  process.exit(1);
});

देखो कि बहीखाता और वित्त एजेंट को क्या दिखाई देगा

कोड, कॉन्फ़िग फ़ाइल या ग्राहक का संदेश पेस्ट करो। बाईं ओर तुम्हारी मूल सामग्री है; दाईं ओर केवल वही है जो AI मॉडल को दिखेगा।

तुम्हारे ब्राउज़र में चलता है, कुछ भी अपलोड नहीं होता
AI क्या देखता है
// config.ts
export const db = "[CONNECTION_STRING_1]";
const apiKey = "[API_KEY_1]";
STRIPE_SECRET_KEY=[API_KEY_2]

// Ticket from [EMAIL_1], phone [PHONE_1]
Refund to IBAN [IBAN_1], card [CARD_1]
7 निजी आइटम छिपाए गए:
1 × पासवर्ड वाला लिंक
2 × API कुंजी
1 × कार्ड नंबर
1 × बैंक खाता (IBAN)
1 × ईमेल पता
1 × फ़ोन नंबर

अन्य AI एजेंटों के लिए कोड

ग्राहक सहायता एजेंटशोध सहायककोडिंग एजेंटबिक्री संपर्क एजेंटसंचालन ऑटोमेशन एजेंटकई एजेंटों की शोध टीमवॉइस फ़ोन एजेंटनिजी, सेल्फ़-होस्टेड एजेंटडेटा विश्लेषक एजेंटनिजी सहायककॉन्टेंट और SEO लेखकसोशल मीडिया मैनेजरभर्ती सहायकअनुबंध समीक्षा एजेंटऑनलाइन स्टोर सहायकAI ट्यूटरवेब ब्राउज़िंग एजेंटसुरक्षा अलर्ट की प्राथमिकता तय करने वाला एजेंटDevOps घटना प्रतिक्रिया एजेंटमीटिंग नोट्स सहायकप्रोजेक्ट मैनेजर एजेंटइनबॉक्स छँटाई एजेंटअनुवाद और स्थानीयकरण एजेंटवीडियो निर्माण एजेंटडिज़ाइन और स्लाइड्स एजेंटक्लिनिकल नोट्स लिखने वाला एजेंटबैक-ऑफ़िस RPA एजेंटस्वायत्त लक्ष्य एजेंटसाथी किरदार एजेंट