המשימות של עומרי

עוזר ה-AI (האקי) · גרסה 6.1 · 30.09.2026 · כולל נושא אחד לעידו

מה שדורש קוד בשרת כדי שהאקי יענה נכון. כל ההפניות הן לקוד השרת, ענף stg.

כלל העבודה, החלטה של אייל: לא נוגעים בקיים. לא משנים סקיל קיים ולא משנים פלואו קיים. כל סקיל וכל פלואו שהאקי צריך משוכפל, עם קידומת שמזהה אותו כשלנו, והשינויים נעשים רק בעותק. כך וואטסאפ, המסכים וכל פלואו אחר ממשיכים לעבוד בדיוק כמו היום.

קוד קראתי את זה בקוד השרת נמדד מדדתי בפרוד, בריצה או בקריאת API השערה לא נבדק קטן בינוני גדול הערכת מאמץ שלי, לא מחייבת

מה משכפלים, ובאיזה שם

הקידומת לסקילים: haki_. הקידומת לשמות הפלואים: "האקי ·". אם יש לך מוסכמה אחרת, תחליף, העיקר שתהיה אחת.

הקיים, נשאר בלי שינויהעותק שלנומשימות
get_company_accountshaki_get_company_accounts1
cashflow_analyzehaki_cashflow_analyze2, 3, 4
get_monthly_reporthaki_get_monthly_report5, 6, 9
fetchTransactionsByDate, filterTransactionshaki_fetchTransactionsByDate, haki_filterTransactions3, 6, 9
פלואו 36, חיפוש וסינון תנועותפלואו חדש "האקי · חיפוש וסינון תנועות", שקורא לסקילים המשוכפלים3, 6, 9
פלואו 35, חיפוש שאלות קיימותפלואו חדש "האקי · חיפוש שאלות קיימות", רק אם יידרש בו שינוי
get_company_meetingshaki_get_company_meetings8
create_taskhaki_create_task14
איןhaki_get_company_credit_cards13
איןhaki_get_company_data_status10
פלואו 61 בסטייג'ינג, המלצת תשלוםפלואו 68 בפרוד (כבר קיים, עותק)15
פלואו 56, צ'אט יועץפלואו 57 (כבר קיים, עותק)
פלואו 58, צ'אט לקוחפלואו 59 (כבר קיים, עותק)

גם הפונקציות המשותפות. סקיל משוכפל לא משנה פונקציה שגם הסקיל המקורי קורא לה. למשל buildCashflowAggregate, parseStoredMonthlyReports, getMeetingsByCompany, handleCashflowMessage. כשצריך התנהגות אחרת, כותבים פונקציה חדשה לידן, עם אותה קידומת.

מעבר ללקוחות. כשאייל מאשר, הלקוחות עוברים לפלואים החדשים דרך כללי הניתוב, בלי לערוך את 56 ו-58. כך החזרה אחורה היא שינוי של כלל ניתוב אחד. היום מנותב לעותקים רק המשתמש של אייל.

מה אי אפשר לשכפל

ארבעה דברים הם תשתית משותפת ולא סקיל או פלואו. כל אחד מהם דורש אישור נפרד של אייל לפני שנוגעים בו:

מהלמה אי אפשר לשכפלאיך מצמצמים את הסיכוןמשימה
נתונים חלקיים בקריאה עם ימים (עידו)הבאג בשירות הסנכרון, שמשרת גם את המסכיםזה תיקון באג ולא שינוי התנהגות. לחלופין, הסקילים המשוכפלים קוראים תמיד חודשים שלמים ומסננים את הימים בעצמם.לעידו
אכיפת עיגון הנתוניםרצה בתוך מנוע ה-AFCמתג לפי פלואו, כבוי כברירת מחדל. נדלק רק בעותקים.11
מודלי Gemini 3קריאת התשובה נעשית במנועתוספת למודלים חדשים בלבד. מודל 2.5 ממשיך במסלול הקיים.12
טוקנים ושגיאות ב-traceה-trace נכתב במנועשדות חדשים בלבד, בלי לשנות שדות קיימים12

מה הוחלט

#החלטה של איילמה זה אומר לקוד
0לא נוגעים בסקילים ובפלואים הקיימים. משכפלים עם קידומת.כל המשימות למטה נעשות בעותקים.
1אותם כלים שיש היום, בלי לבנות סט חדשהעותקים שומרים על אותו תפקיד של המקור. נוספים שני סקילים: כרטיסי אשראי (13) ומצב הנתונים (10).
2cashflow_report יורד מהאקיהוא לא משוכפל ולא מחובר לעותקים. הסקיל המקורי נשאר כמו שהוא.
3רווח = הפרש תזרימי תפעוליהשדה כבר נקרא כך בפלט. ההגדרה נאכפת בהנחיות.
4חריגה נמדדת לפי היתרה המאוחדת. חשבון בודד מתחת למסגרת הוא התרעה.משימה 4.
5נגררות הן תזרים לכל דברנכללות בתנועות הצפויות, מסומנות (משימה 2).
6"כמה צפוי" = סך התחזית, והתשובה מפרידה בין מה שכבר רשום להערכהסימון לכל תנועה עתידית (משימה 3).
7יעדים הם חלק מהדוח החודשי. ללקוח מוצג רק יעד שנפתח לו.משימה 5.
9מצב הנתונים מוזרק לפני האקי, חי בכל שאלהמשימה 10.
10כרטיסי אשראי הם סקיל חובהמשימה 13.
11האקי יכול לפתוח משימה למנהל התזריםמשימה 14.

הכלים של האקי אחרי השינוי

כליעונה עלגבולמשימות
haki_get_company_accountsיתרה, מסגרת ופנוי, לכל חשבון ומאוחדרק עכשיו1
haki_get_monthly_reportהתמונה הכוללת של העבר: הכנסות, הוצאות, הפרש תפעולי, הרכב, יעדיםרק עבר5, 6, 9
"האקי · חיפוש וסינון תנועות"סכום של משהו מסוים: קטגוריה, ספק, לקוח, אמצעי תשלוםתמיד עם נושא3, 6, 9
haki_cashflow_analyzeעתיד: יתרה, חריגה, תנועות צפויות, נגררותרק עתיד2, 3, 4
haki_get_company_meetingsפגישות שהיו והפגישה הבאה8
haki_get_company_credit_cardsכרטיסי אשראי: החיוב הבא, מה כבר נצבר, עסקאות ותשלומיםרק כרטיסים13
haki_create_taskפתיחת משימה למנהל התזרים. זו פעולה, לא שאלה.רק באישור הלקוח14

חלוקת העבודה בינינו. אתה כותב את הסקילים המשוכפלים ב-skills.registry.js. אני מחבר אותם לעותקים של הפלואים (57, 59, 68) דרך ה-API: התיאור והפרמטרים שהמודל רואה נמצאים בהגדרת הכלי בפלואו (agentConfigs[].afc.tools[], נבנה ב-afcRunner.service.js:178). כשסקיל מוכן בסטייג'ינג, תגיד לי את השם ואת הפרמטרים הסופיים.

סדר העבודה

#משימהאיפהמאמץלמה
1יתרה ומסגרת לכל חשבוןhaki_get_company_accountsקטןהיום אין כלי שעונה על שאלה לפי חשבון
2תנועות צפויות עם קטגוריה וסינוןhaki_cashflow_analyzeגדולהיום רק 5 הגדולות נראות
3סימון רשום מול הערכהhaki_cashflow_analyze, עותק החיפושבינוניהחלטה 6
4חריגה לפי היתרה המאוחדתhaki_cashflow_analyzeבינוניהחלטה 4, ואייטם #422
5יעדים בדוח החודשיhaki_get_monthly_reportבינוני19 תשובות שגויות ב-100 השאלות של אייל
6מקור אחד, פירוט חודשי, חודש חלקיעותקי הדוח והחיפושבינוניאותה שאלה נתנה שני מספרים
7שגיאה מפורשת במקום אפסיםכל העותקיםבינוני#413, פתוח
8תיקון limit, והפגישה הבאהhaki_get_company_meetingsקטןמחזיר ריק כשיש פגישות
9נפח הפלטעותקי הדוח והחיפושקטןעד 135 אלף תווים לשאלה
10מצב הנתונים, כשלב בפלואוhaki_get_company_data_statusקטןהחלטה 9
11עיגון נתונים: קריאת הלוג ואכיפהתשתית משותפתקטן לקריאה, בינוני לאכיפה2 עד 3 אחוזים מהתשובות עם סכום בלי מקור
12מודלי Gemini 3, ו-traceתשתית משותפתבינוני4 מודלים נכשלים אחרי קריאת הכלי הראשונה
13כרטיסי אשראי (חובה)haki_get_company_credit_cardsבינוני16 תשובות שגויות ב-100 השאלות של אייל. הנתונים כבר קיימים בשרת.
14משימה למנהל התזרים (חובה)haki_create_taskקטןעותק של הקיים, עם הגנות

המספור לא משקף עדיפות למשימות 13 ו-14: אייל הגדיר אותן כחובה. הן נוספו בסוף כדי לא לשנות את המספרים של שאר המשימות.

המשימות בפירוט

בכל משימה, "היום" מתאר את הסקיל המקורי, שנשאר בלי שינוי. "נדרש" מתאר את העותק.

1

יתרה ומסגרת לכל חשבון

haki_get_company_accountsקטן
היום
קוד skills.registry.js:2660. ה-handler קורא ל-getRawCashflowAccounts ומחזיר רק bankId, accountNickName, bankSnifId, bankAccountId, accountId. היתרה והמסגרת נשלפות ונזרקות.
עוד פרט
קוד ה-itemFields מצהיר על accountUUID, וה-handler מחזיר accountId. שווה ליישר.
נדרש
להוסיף לכל חשבון יתרה, מסגרת ופנוי, ושורת סיכום מאוחדת נפרדת. אם יש בנתונים תאריך עדכון של המסגרת, להחזיר גם אותו: יש מקרים שהמסגרת אצלנו ישנה מזו שבבנק.
סימן המסגרת
נמדד ב-getForecast המסגרת חוזרת כמספר שלילי (credit_limit: -100000). ב-#411 תוקן החישוב של הפנוי ב-cashflow_analyze. כאן צריך אותו חישוב, כדי ששני הכלים לא יחזירו פנוי שונה.
#411 בפרוד
נמדד 29.09 בפרוד: יתרה 25,987- ומסגרת 100,000- החזירו available_funds: -125987. התיקון עוד לא עלה לפרוד.
בדיקה
"כמה מסגרת פנויה יש לי בכל חשבון?" על חברות 4, 70, 432. משווה מול accounts[] ב-get-cashflow-widget-data.
// out
{ "accounts": [
    { "accountId": "f140e823-…", "account_name": "פועלים 170132", "bankAccountId": "170132",
      "current_balance": -45852, "credit_limit": 50000, "available": 4148,
      "is_over_limit": false, "limit_updated_at": "2026-09-01" } ],
  "consolidated": { "current_balance": -25987, "credit_limit": 100000, "available": 74013 },
  "as_of": "2026-09-29T08:52:04Z" }
2

תנועות צפויות עם קטגוריה וסינון

haki_cashflow_analyzeגדול
היום
קוד שרשרת הקריאה: skills.registry.js:1186 ← chat.logic.js:2565 handleMonthlyCashflowAnalyze ← IncomingMessageHandler.handleCashflowMessage. ה-resultMap נבנה ב-IncomingMessageHandler.js:1903 עם שלושה שדות לתנועה: description, amount כטקסט מעוצב, is_expense.
מה חסר
  • קוד buildCashflowAggregate (:191) משתמש ברשימת התנועות רק לדירוג 5 הגדולות. הרשימה עצמה לא חוזרת.
  • קוד אין קטגוריה, מזהה תנועה, חשבון, אמצעי תשלום או תאריך מקורי. הם נחתכים ב-handleCashflowMessage, לפני הכלי.
  • קוד לתנועה עתידית יש קטגוריה עסקית ב-transTypeId. ב-getForecast השדה category מתמלא מ-transTypeName || category || paymentDesc (cashflowWidget.service.js:128). נמדד בפועל חזר תמיד אמצעי התשלום.
שתי דרכים
  • א. להוסיף שדות ב-handleCashflowMessage. לא מתאים לכלל העבודה: הקוד משרת גם את וואטסאפ.
  • ב. שהכלי יקרא מ-CashflowWidgetService.getForecast (:415), שמשרת את הדשבורד. שם כל תנועה כבר מגיעה עם id, date, original_date, account_id, account_name, description, category, amount, is_carry, end_day_balance.
לכן ב: העותק קורא מ-getForecast בלי לשנות אותו. האקי והדשבורד יציגו אותם מספרים, ואפשר לבדוק מספר מול מספר.
נדרש
בלי הפרמטרים החדשים, הפלט נשאר כמו היום. עם include_transactions חוזרת רשימה מסוננת, עם סכום ומספר של כל מה שעבר את הסינון, ועד 50 שורות. נגררות נכללות ברשימה, מסומנות, עם התאריך המקורי.
קטגוריה
צריך גם את המזהה וגם את השם. יש מיפוי ב-BiziboxUtils.js:846 (transTypes.get(trans.transTypeId)). השערה לא בדקתי אם לכל תנועה עתידית יש transTypeId.
דחיית עבר
כש-end_date לפני היום: {error: "PAST_RANGE"}. היום המודל פונה לכלי הזה בשאלות עבר: 7 מתוך 7 תשובות רווח דרכו היו שגויות. קוד קיים כבר מנגנון דומה, clampArgsToDataStart ו-buildOutOfRangeOutput ב-src/utils/dataStartFrom.js:124, 188.
תאריכים חסרים
נמדד כשהמודל קורא לכלי בלי start_date ו-end_date, הכלי מחזיר בשקט טווח של כשבוע. "מתי צפויה חריגה?" נענה "לא צפויה" על סמך 4 ימים. נדרש: טווח ברירת מחדל של 30 יום, וה-period שנלקח בפועל תמיד בפלט (קיים היום).
הפרמטר tense
העותק הוא עתיד בלבד, ולכן אין בו פרמטר tense. כ-103 שגיאות בבדיקות היו סתירה בין tense לתאריכים.
// in: existing start_date, end_date, account_id, plus
{ "include_transactions": true,
  "direction": "income",            // income | expense | all
  "search": "שכר דירה",             // matches description
  "category": "קניות מלאי וחלפים",  // name or key id
  "payment_method": "צ'ק",
  "only_carry": false }

// out: everything that exists today, plus
"filtered": { "sum": 215741, "count": 12, "truncated": false },
"transactions": [
  { "id": "5c47b9b3-…", "date": "2026-10-10", "original_date": "2026-10-10",
    "description": "…", "amount": 28000, "is_expense": false,
    "category_key_id": "…", "category_name": "הכנסות ממכירות",
    "payment_method": "העברה בנקאית",
    "account_id": "f140e823-…", "account_name": "פועלים 170132",
    "is_carry": false, "is_estimate": false } ]
3

סימון רשום מול הערכה

haki_cashflow_analyze · עותק החיפושבינוני
ההחלטה
התשובה היא סך התחזית, והיא מפרידה בין מה שכבר רשום להערכה. האקי אומר ללקוח "הערכה" בלבד. את הניסוח אני מטפל בהנחיות.
הרקע
קוד שורה תקציבית מנוהלת (Future_Cashflow_Budget_Lines) כותבת לביזיבוקס תנועות עתידיות בשם תקציב <שם קטגוריה>, בגובה הפער: יעד פחות בוצע פחות רשום. workspace-budget-lines.js:259.
היום
  • קוד buildCashflowAggregate סופר תנועות כאלה כתנועות רגילות. הן יכולות להופיע ב-5 ההכנסות הגדולות.
  • נמדד בתחזית לאוקטובר: חברה 4, 119,594 ₪ בשורות "תקציב". חברה 70, 787,000 ₪. חברה 432, 231,061 ₪ בשורות "צפי".
  • קוד בקוד הבקרה הזיהוי הוא לפי תחילת התיאור, "תקציב" או "צפי" (cashflowReview/rules/helpers.js:141).
נדרש
is_estimate לכל תנועה עתידית, ופיצול של כל סכום לשניים: רשום והערכה. בשני המקומות: cashflow_analyze (סכומים כלליים ו-filtered), ופלואו 36 במצב עתיד.
שאלה אליך
איך מזהים הערכה בוודאות? לפי תחילת התיאור, או שיש שדה או קישור לטבלת השורות התקציביות. ומה ההבדל בין "תקציב" ל"צפי": מי יוצר כל אחד.
לא להתבלבל
קוד cashflowKnownTotal בדוח החודשי סופר רק תנועות עם isCashFlow (CompanyService.js:2161). הוא לא "כל מה שאינו הערכה". נמדד חברה 70, קניות חומרי גלם, אוקטובר: total 198,834, cashflowKnownTotal 1,199.
// out: cashflow_analyze totals, and flow 36 in future mode
"totals": { "total_income": 215741,
            "income_recorded": 96147, "income_estimate": 119594,
            "total_expenses": 216810,
            "expenses_recorded": 216810, "expenses_estimate": 0 }
4

חריגה לפי היתרה המאוחדת

haki_cashflow_analyzeבינוני
היום
קוד is_deviation נקבע לפי הצבע של ביזיבוקס: uniItraColor === 'RED'. cashflowWidget.service.js:162, IncomingMessageHandler.js:1918.
הבעיה
השערה לפי ממשק חדש (אייטם #422): 14 מתוך 87 חברות מסומנות "חריגה צפויה" כשהיתרה המאוחדת בתוך המסגרת, כולן עם כמה חשבונות. לא בדקתי בעצמי.
נמדד חברה 4, טווח 14 יום: end_balance 27,459 חיובי, ו-risk: "bad" עם חריגה ב-11.10.
נדרש
שני סימונים נפרדים בפלט:
  • deviation: היתרה המאוחדת ליום מול סך המסגרות. זו החריגה של העסק.
  • account_alerts[]: חשבון בודד שיורד מתחת למסגרת שלו, עם החשבון שממנו אפשר להעביר.
חשד
השערה לפי ההערה ב-cashflowWidget.service.js:449, תגובה משותפת של ביזיבוקס יכולה להשמיט חשבונות שלא השתנו. אם כן, היתרה היומית המאוחדת עלולה להיות חסרה. בדוח של 27.09 נמצאה סטייה קבועה של 24,367 ₪, בגודל של חשבון אחד.
"deviation": { "has_deviation": false, "first_deviation_date": null, "days": [] },
"account_alerts": [
  { "account_id": "…", "account_name": "פועלים 170132", "date": "2026-09-30",
    "projected_balance": -56300, "credit_limit": 50000, "over_by": 6300,
    "can_transfer_from": [ { "account_id": "…", "account_name": "מזרחי 445", "available": 38000 } ] } ]
5

יעדים בדוח החודשי

haki_get_monthly_reportבינוני
היום
קוד הדוח לא מחזיר יעדים. נמדד המודל פונה במקום זה ל-cashflow_analyze: 13 מתוך 15 תשובות שגויות.
המקור
קוד טבלת Future_Cashflow_Targets (futureCashflowTarget.models.js): company_id, year_month_key, section, category_name, category_key_id, target_amount, average_amount, is_target_changed, open_target_for_client.
ההחלטה
ללקוח מוחזר רק יעד עם open_target_for_client = true. הסימון אומר שהיועץ קבע שזה יעד. שורה בלי הסימון היא ערך פתיחה אוטומטי, ולא יעד.
נדרש
  • פרמטר include_targets. בלעדיו הפלט כמו היום.
  • לכל קטגוריה ולכל חודש: יעד, ביצוע, נשאר, אחוז ניצול, מצב. החישוב בכלי, לא במודל.
  • שיוך היעד לשורה בדוח לפי category_key_id, ואם אין, לפי שם. כך זה נעשה ב-workspace-budget-lines.js:388 findParent.
  • קטגוריה בלי יעד פתוח: target: null. חברה בלי אף יעד פתוח: has_targets: false.
מלכודת
קוד ב-cashflowReview/inputs.js:119 "פער" הוא יעד פחות ממוצע. כאן צריך יעד פחות ביצוע.
שאלה אליך
איך הסקיל יודע שהשואל הוא בעל העסק ולא איש צוות? ההצעה שלי: פרמטר audience שאני קובע בהגדרת הפלואו (58 ו-59 לקוח, 56 ו-57 צוות), בלי שהמודל שולט בו. אפשר להגדיר בפלואו פרמטר קבוע שהמודל לא רואה?
צוות
השערה בצד של היועץ (פלואו 56) ההצעה שלי היא להחזיר את כל היעדים, עם open_for_client לכל אחד. אייל עוד לא הכריע.
// in
{ "start_year": 2026, "start_month": 9, "end_year": 2026, "end_month": 9, "include_targets": true }

// out: each category gains
{ "categoryName": "פרסום ושיווק", "total": -23400,
  "target": 20000, "remaining": -3400, "used_pct": 117, "target_status": "over" }
// top level
{ "has_targets": true, "partial_month": true, "as_of": "2026-09-29" }
6

מקור אחד, פירוט חודשי, חודש חלקי

haki_get_monthly_report · haki_fetchTransactionsByDateבינוני
היום
קוד שני הסקילים קוראים מאותו מקור, עם אותו תנאי: isDailyMode = start_day && end_day (skills.registry.js:1757, :1274). עם ימים: חי מ-getDailyCashflowData. בלי ימים: טבלת Bizibox_Company_Monthly_Report.
הבעיה
נמדד אותה שאלת רווח, באותו יום, החזירה 81,369.59 ו-92,153.93. השערה הסיבה היא שפעם המודל צירף ימים ופעם לא.
באג בטווח
קוד parseStoredMonthlyReports (:565) מחבר את כל החודשים בטווח לסכום אחד, בלי פירוט לפי חודש. הוא מחבר גם את שורות היתרה: בטווח של שלושה חודשים, "יתרת פתיחה בנק" היא הסכום של שלוש יתרות הפתיחה, ו"יתרת סגירה בנק" הסכום של שלוש יתרות הסגירה. המספרים האלה חסרי משמעות.
למה זה חשוב
בגלל זה ההנחיות מחייבות היום קריאה נפרדת לכל חודש. נמדד 432 מתוך 432 קריאות היו לחודש בודד, ושאלת מגמה של 9 חודשים עולה 9 קריאות ו-135 אלף תווים.
נדרש
  • ליישר את שני המצבים לאותו מקור. אם אי אפשר, להחזיר source: "stored" | "live" ו-as_of.
  • by_month[] לכל שורה, כך שקריאה אחת על טווח מחזירה גם את הפירוט החודשי.
  • בטווח של כמה חודשים: יתרת הפתיחה של החודש הראשון, ויתרת הסגירה של החודש האחרון. לא סכום.
  • partial_month: true כשהטווח כולל את החודש הנוכחי.
  • סכום לכל הטווח (range_total) לכל שורה, כדי שהמודל לא יחבר חודשים בעצמו.
מה אני עושה
כלל בהנחיות: חודשים שלמים נשלחים בלי ימים. זה מקטין את הבעיה ולא פותר אותה, כי שאלה על חצי חודש עדיין תקרא חי.
עתיד
קוד fetchTransactionsByDate עם tense: 'future' ובלי ימים קורא future_data (:1312). get_monthly_report קורא רק data. החודש הנוכחי לא כלול בעתיד (CompanyService.js:4138).
נתונים חלקיים עם ימים
קריאה עם ימים בתוך החודש הנוכחי מחזירה נתונים חלקיים. הפירוט, והטיפול, אצל עידו: למטה. עד שזה מתוקן, העותקים קוראים חודשים שלמים בלבד.
באג במצב עתיד
נמדד 29.09, פלואו 36 עם tense: "future", אוקטובר 2026, level: category, attribute: debit:
  • חברה 4, "קניות מלאי וחלפים": חזר sum: -7292 עם תנועה אחת מקטגוריה אחרת (categoryName: "אחזקת עסק"). ב-get-monthly-cashflow-data עם includeFutureData הקטגוריה הזו מציגה 52,445.
  • חברה 70, "קניות חומרי גלם": חזר sum: 0, data: null. באותו endpoint הקטגוריה מציגה 198,834.
עד שזה מתוקן, בסביבת החול החיפוש מוגדר ככלי עבר בלבד, והאקי אומר ללקוח שאין לו חלוקה של התחזית לפי קטגוריה.
7

שגיאה מפורשת במקום אפסים

#413בינוני
היום
נמדד חברה בלי חיבור לבנק מקבלת אפסים, והאקי עונה "לא צפויה חריגה". קוד בכשל הסקילים מחזירים null, [] או אובייקט ריק (:1798, :2674, :1193).
נדרש
קודמתי
NO_DATAאין חיבור לבנק, או אין נתונים בטווח. עם reason ו-message_he.
UNKNOWN_ACCOUNTמזהה חשבון שלא שייך לחברה. עם רשימת החשבונות. היום הכלי מחזיר בשקט את כל החשבונות.
PAST_RANGE / FUTURE_RANGEכלי עתיד קיבל עבר, או להפך
TOOL_ERRORכשל פנימי. לא להחזיר null.
הכלל
sum: 0 חוזר רק כשיש נתונים ואין תנועות שמתאימות.
מה כבר נעשה
קוד בסטייג' (קומיטים מ-28.09, לוח #413): cashflow_analyze המקורי מחזיר data_status: ok | empty_period | unavailable, ובמצב unavailable כל שדה מדידה הוא null. handleCashflowMessage זורק שגיאה במקום להחזיר מחרוזת. נמדד ב-29.09 זה עוד לא היה בפרוד. העותק haki_cashflow_analyze יורש את זה; נשאר להוסיף את אותה התנהגות בעותקים של הדוח החודשי והחיפוש, ואת UNKNOWN_ACCOUNT.
מזהה חשבון
קוד ב-cashflow_report המזהה מתקבל גם כ-UUID וגם כמספר חשבון (:1064). שווה להעתיק את זה לכל סקיל שמקבל חשבון. נמדד המודל העביר מספר חשבון במקום UUID, וקיבל 780,450 במקום 597,035.
8

תיקון limit, והפגישה הבאה

haki_get_company_meetingsקטן
היום
קוד meetings.logic.js:3058 getMeetingsByCompany: ה-limit מוחל על השאילתה, ורק אחר כך מסוננות פגישות בלי סיכום (if (meetingSummary)). נמדד בחברה 70, limit: 1 החזיר ריק.
נדרש
  • לשלוף יותר ולחתוך ל-limit אחרי הסינון.
  • פרמטר upcoming: הפגישה הקרובה עם status = 'scheduled' ו-scheduled_at בעתיד. היום השאילתה מסננת רק approve ו-processed.
עוד פרט
קוד תאריך הפגישה נלקח מ-created_at לפני scheduled_at (:3083). אם הפגישה נוצרה ביום אחר מזה שבו התקיימה, התאריך שהאקי אומר יהיה שגוי.
// in
{ "limit": 3, "upcoming": true }
// out
{ "meetings": [ … ],
  "next_meeting": { "scheduled_at": "2026-10-06T10:00:00+03:00", "title": "…", "location": "…" } }
9

נפח הפלט

haki_get_monthly_report · עותק החיפושקטן
נמדד
קריאהתווים
get_monthly_report, חודש אחד15 עד 19 אלף
שאלת מגמה, 9 חודשים, 9 קריאות135,279
חיפוש משכורות, 3 קריאות8,982
חיפוש בלי נושא, חצי שנה116,064
חיפוש לפי אמצעי תשלום200 עד 84,148
מהלוג שלך: ריצה אחת הגיעה ל-89,200 טוקנים.
נדרש
  • get_monthly_report: פרמטר level: headers | categories | descriptions, ברירת מחדל categories. ופרמטר categories[] לסינון.
  • אחרי שמשימה 6 תוסיף by_month[], אני מבטל בהנחיות את החובה לקרוא לכל חודש בנפרד.
  • חיפוש בלי נושא (no_filtering): להחזיר sum, count, by_month[] ועד 50 התנועות הגדולות, עם truncated.
שאלה אליך
למה הפלט של חיפוש לפי אמצעי תשלום משתנה בין 200 ל-84 אלף תווים לאותו סוג שאלה? ולמה פלואו 36 לקח 8 עד 42 שניות לקריאה בחברה 4?
10

מצב הנתונים, כשלב בפלואו

haki_get_company_data_statusקטן
הרעיון
סקיל שרץ כשלב רביעי בקבוצה המקבילה "מנוע האקי", ליד בסיס הידע, הפרופיל והקטגוריות. התוצאה מוזרקת להקשר של האקי. המודל לא קורא לו, ולכן הוא לא מוסיף כלי.
מה מחזיר
רשימת חשבונות עם מזהים, מתי סונכרן כל חשבון, האם יש חיבור לבנק, טווח התאריכים שיש בו נתונים, האם יש יעדים פתוחים ללקוח.
בלי סכומים
יתרה ומסגרת לא נכנסות לכאן. אם הן יוזרקו, המודל יענה מההקשר בלי לקרוא לכלי, והתשובה תיפול בעיגון, כי טקסט מוזרק לא נרשם כמקור.
המקור
נמדד getForecast כבר מחזיר data_health (status, is_stale, last_success_at, bank_updated_at), last_updated_at ו-source_ranges[] לכל חשבון.
מהירות
השערה השלב רץ במקביל, ולכן לא אמור להאריך את התשובה. צריך שליפה מהירה, אולי עם useDailyCache. לא מדדתי.
מה אני עושה
מוסיף את השלב לפלואים ומוסיף להנחיות איך להשתמש בו. עד שהסקיל מוכן אני יכול להוסיף שלב עם get_company_accounts הקיים, שנותן את רשימת החשבונות והמזהים.
// out
{ "has_bank_connection": true, "status": "ready", "is_stale": false,
  "last_success_at": "2026-09-29T08:52:04Z", "bank_updated_at": "2026-09-29T02:33:20Z",
  "data_from": "2025-01-01",
  "has_targets_for_client": true,
  "accounts": [ { "accountId": "f140e823-…", "account_name": "פועלים 170132", "bankAccountId": "170132" } ] }
11

עיגון נתונים: קריאת הלוג ואכיפה

monetaryGrounding.service.jsבינוני
המטרה
שהאקי לא ימסור ללקוח סכום שלא הגיע מכלי. הדוגמה של אייל: המודל עונה מהזיכרון סכום של הכנסות.
מה קיים
קוד שלב א', לוג בלבד, ב-monetaryGrounding.service.js:
  • רישום. כל פלט גולמי של סקיל או פלואו נסרק למספרים, שנרשמים על ה-runtimeCtx של הריצה (recordSourceOutput, :191). פלט של סוכן ופלט של כלי המסירה לא נרשמים.
  • בדיקה. בשלושת כלי המסירה, בהם save_chat_message (skills.registry.js:3304), הטקסט נסרק לסכומי כסף בלבד (extractMoneyFigures, :288): מספר עם סימן מטבע או מפריד אלפים, וגם ערכים בתוך בלוק chart.
  • התאמה. ערך מדויק, או צורת עיגול של ערך מקור (indexForms, :55). אפס לא נחשב מקור.
  • לוג. שורה אחת ב-Monetary_Grounding_Misses לכל תשובה עם סכום לא מותאם, עם ungrounded_values[].nearest, registry_size, tool_names, is_test, process_id.
מה חסר
  • קוד לטבלה אין route. היא מופיעה רק בשירות, במודל ובפטור ב-UserAccountModelScopeService.js:46. אי אפשר לקרוא אותה בלי גישה למסד.
  • קוד הבדיקה רצה ברקע (checkDeliveredAnswerAsync, :415), אחרי שהתשובה כבר בדרך לשמירה. היא לא יכולה לעצור תשובה.
  • השערה לפי המסמך שלך מ-07.09 המיגרציה לא הורצה אז. לא יודע אם הטבלה קיימת בפרוד.
נמדד
בבדיקות שלי, 28 תשובות עם סכום בלי אף קריאת כלי: 9 נכונות (המספר היה בהנחיות), 17 בלי מקור, ומתוכן 9 שמצטטות כלי שלא נקרא. זה 2 עד 3 אחוזים מהתשובות.
שלב 1: קריאה
  • לוודא שהמיגרציה 20260907120000-create-monetary-grounding-misses רצה בפרוד, ושנכתבות שורות.
  • GET /api/ai-flow-manager/grounding-misses, קריאה בלבד. פרמטרים: from_date, to_date, company_id, flow_id, is_test, channel, min_registry_size.
  • להוסיף לשורה את מספר קריאות הכלי בריצה (tool_calls_count). registry_size = 0 אומר היום גם "לא נקרא כלי" וגם "נקרא כלי שהחזיר ריק", ואלה שני מקרים שונים.
שלב 2: אכיפה
רק למקרה אחד, הברור ביותר:
מקרהזיהויפעולה
סכום בתשובה, ואף כלי לא נקראtool_calls_count = 0לא לשלוח. תור נוסף למודל, עם הודעה שהסכום לא מגובה ושעליו לקרוא לכלי. אם גם התור השני נכשל, הודעה קבועה ללקוח.
עיגולnearest קרובלשלוח. בלי לוג, או לוג ברמה נמוכה.
נקרא כלי, והסכום לא דומה לשום ערךnearest רחוקלשלוח, עם לוג. לא לאכוף עכשיו.
למה לא יותר
קוד לפי המסמך שלך, מספר שהמודל חישב בעצמו נרשם כנפילה. היום האקי מחבר חודשים ומחשב הפרשים, ולכן אכיפה מלאה תחסום תשובות נכונות. אחרי משימות 5 ו-6 הכלים יחזירו סכומים סופיים, ואז אפשר להרחיב את האכיפה גם למקרה השלישי.
איך לאכוף
הבדיקה צריכה לרוץ לפני המסירה ולא אחריה. שתי דרכים:
  • בלולאת ה-AFC, לפני שהתשובה הסופית יוצאת מהסוכן. שם אפשר לתת למודל תור נוסף.
  • ב-save_chat_message, בצורה סינכרונית. שם אפשר רק לחסום. לפי המסמך שלך, כשל שם כבר זורם ל-markPendingAssistantError.
ההמלצה שלי: הראשונה, כי היא מתקנת את התשובה ולא רק חוסמת אותה. ההכרעה שלך.
ההודעה הקבועה
"לא הצלחתי לאמת את הנתון מול הנתונים שלך. אפשר לנסח את השאלה שוב, או לפנות למנהל התזרים." הניסוח הסופי של אייל.
דוגמה
נמדד 29.09, פלואו 57, סשן 9a63fdfb: "מה הרווחיות שלי?" נענה תוך 1.7 שניות, עם turns: [], בסכום של 1,000,000 ₪ ובשורת מקור שמצטטת את הדוח החודשי. בשאלה הבאה המודל קרא לכלי וקיבל 42,518.9-.
שורת המקור
היום המודל כותב בעצמו את השורה "מקור הנתונים", ולכן היא יכולה לצטט כלי שלא נקרא. ההצעה: המנוע בונה את השורה מהקריאות שבוצעו בפועל (afcTrace.turns[].calls[]) ומצרף אותה לתשובה. כשלא נקרא אף כלי, אין שורה.
מתג
אכיפה לפי פלואו, בהגדרת הסוכן (afc.groundingEnforce), כדי שאוכל להדליק אותה קודם בסביבות החול 57 ו-59 ולמדוד כמה תשובות נחסמות.
מה אעשה איתו
סעיף קבוע בדוח היומי של בדיקת ה-AI: כמה תשובות ללקוחות נפלו, לפי שלושת המקרים. והצלבה של כל סבב בדיקות מול הלוג לפי process_id, במקום הבדיקה הידנית שאני עושה היום.
שאלה לאייל
האם סכום שהגיע מההקשר המוזרק (פרופיל החברה, הזיכרון) נחשב מעוגן. היום לא. ההמלצה שלי: לא, כי הזיכרון מתיישן. 9 התשובות הנכונות שמדדתי הן המקרה הזה.
// GET /api/ai-flow-manager/grounding-misses?from_date=2026-09-29&is_test=false
{ "total": 14,
  "rows": [
    { "id": 881, "created_at": "2026-09-29T11:20:03Z", "channel": "save_chat_message",
      "process_id": "90412", "flow_id": "58", "company_id": 70, "is_test": false,
      "tool_calls_count": 0, "registry_size": 0, "tool_names": [],
      "checked_count": 2, "ungrounded_count": 2,
      "ungrounded_values": [ { "raw": "14,000 ₪", "value": 14000, "source": "text", "nearest": null } ],
      "delivered_text": "…" } ] }
12

מודלי Gemini 3, ו-trace

afcRunner.service.js · gemini.service.jsבינוני
נמדד
מודלנכונות, 5 שאלותזמן ממוצע
gemini-3.1-flash-lite5 מ-57.7 שניות
gemini-2.5-flash (הנוכחי)4 מ-5, המצאה אחת9.5 שניות
gemini-3-flash-preview, gemini-3.5-flash5 מ-516.1 שניות
gemini-2.5-flash-lite2 מ-5
3.5-flash-lite, 3.6, 3.7, 3.8נכשלים אחרי קריאת הכלי הראשונה. afc stop=error, הפלט "content is required", והסשן מסומן COMPLETED.
5 שאלות על חברה אחת. זה מדגם קטן, מספיק לכיוון ולא להחלטה.
מהלוג שלך
בריצה של 3.8 המודל צרך 28 אלף טוקני מחשבה ו-7,800 טוקני פלט, ולא חזרה תשובה. כלומר המודל ענה, והמנוע לא קרא את התשובה. האבחנה הקודמת שלי (דחיית חתימה) הייתה שגויה.
היום
קוד afcThinkingConfig (afcRunner.service.js:672) מעביר רק thinkingBudget. נמדד ב-3.8 עם thinkingBudget: 1024 הכישלון זהה. ב-cashflowReview/ai/gemini.js:120 כבר יש שימוש ב-thinkingLevel.
נדרש
  • לקרוא נכון את התשובה של מודלי 3 אחרי קריאת כלי.
  • תמיכה ב-afc.thinkingLevel בהגדרת הסוכן.
  • תשובה ריקה או שגיאה: ניסיון נוסף, ואז הודעת שגיאה ללקוח. הסשן לא מסומן COMPLETED.
  • ב-afcTrace לכל תור: usage {input, thinking, output} ו-error עם הטקסט האמיתי. היום שגיאת Gemini נכתבת רק ללוג.
שאלה אליך
afcTrace נשמר בשלושה עותקים לכל קריאה, ויש סימון retryOf. זה מכוון? בדוח היומי אני מסנן כפילויות לפי מזהה הקריאה.
13

כרטיסי אשראי

haki_get_company_credit_cardsבינוני
היום
נמדד אין כלי לכרטיסים, והמודל פונה לחיפוש התנועות: 10 תשובות שגויות ו-2 נכונות. אותה שאלה נתנה 4 עד 5 סכומים שונים לחברה, מ-79 אלף עד 2.6 מיליון.
מה קיים
קוד CreditCardChargesService.getForCompany(companyId, {months}), CreditCardChargesService.js:175. משרת היום את המסך (GET /api/companies/:companyId/credit-card-charges, routes/companies.js:21) ואת בקרת התזרים. לא מחובר לשום סקיל. לא דורש משתמש.
מה הוא מחזיר
נמדד חברות 4, 70, 432:
  • לכל כרטיס: cardName, lastFour, issuer, bankAccountId, bankAccountName, billingDay, balanceLastUpdatedDate, isStale, openCycle {billingDate, total, count, isEstimate}, ו-cycles[] של עד 3 חודשים.
  • לכל עסקה: purchaseDate, billingDate, isOpenCycle, merchant, categoryKeyId, categoryName, section, amount, originalAmount, originalCurrency, installment {number, of}, isRefund.
הבעיה
נמדד הפלט המלא הוא 104 עד 152 אלף תווים לחברה (227 עד 329 עסקאות). אי אפשר להעביר אותו להאקי כמו שהוא.
נדרש
  • תמיד: סיכום לכל כרטיס, וסיכום כולל לכל הכרטיסים. בלי רשימת עסקאות.
  • עם include_charges: רשימת עסקאות מסוננת, עם סכום ומספר של כל מה שעבר את הסינון, ועד 50 שורות.
  • סינון לפי כרטיס, מחזור (פתוח או סגור), בית עסק, קטגוריה, ורק תשלומים.
  • סיכום לפי קטגוריה למחזור (by_category[]), מחושב בסקיל.
תשלומים
קוד השירות מוציא בכוונה תשלומים ששייכים למחזורים שאחרי החיוב הבא (ההערה ב-:146). לכן "כמה נשאר לי לשלם בתשלומים" דורש חישוב נוסף: יתרת התשלומים לכל עסקה, לפי installment.number ו-of. השערה הסכום של תשלום עתידי שווה לסכום של התשלום הנוכחי. לא בדקתי.
לשים לב
  • openCycle.isEstimate תמיד true: הסכום של המחזור הפתוח הוא מה שנצבר עד עכשיו, ולא הסכום הסופי. הסקיל מחזיר את הסימון, והאקי יאמר "עד עכשיו נצבר".
  • isStale: נמדד בחברות 4 ו-432 יש כרטיסים שלא התעדכנו. אחד מהם מ-2020. כרטיס כזה חוזר מסומן, בלי חיוב הבא.
  • אין מסגרת לכרטיס בנתונים, רק לחשבון הבנק.
  • חברה בלי כרטיסים: {has_cards: false}, לא רשימה ריקה בשקט.
הגבול
החיוב של הכרטיס מופיע גם בתחזית היומית כתנועה אחת (נמדד "צפי עבור..." בחברות 70 ו-432). בתיאור הכלים אני קובע: שאלה על הכרטיס עצמו הולכת לסקיל הזה. שאלה על היתרה בבנק אחרי החיוב הולכת ל-cashflow_analyze.
בדיקה
שאלות P20 ו-E081 עד E090 מבנק השאלות, על חברות 4, 70, 432. משווה מול ה-endpoint של המסך.
// in
{ "months": 3,
  "include_charges": false,
  "card": "8679",                 // last four or card id
  "cycle": "open",                // open | closed | all
  "merchant": "…", "category": "…",
  "only_installments": false }

// out
{ "has_cards": true, "as_of": "2026-09-29",
  "total_next_charges": 58256.82,
  "cards": [
    { "card_name": "…", "last4": "8679", "issuer": "visa",
      "bank_account_id": "f140e823-…", "bank_account_name": "מזרחי 218283",
      "billing_day": 15, "is_stale": false, "updated_at": "2026-09-29",
      "next_charge": { "date": "2026-10-15", "amount": 27973.68, "count": 24, "is_estimate": true },
      "previous_charges": [ { "date": "2026-09-15", "amount": 38614.86, "count": 27 } ],
      "installments_remaining": { "amount": 18600, "count": 6 },
      "by_category": [ { "category_name": "אחזקת רכב ונסיעות", "amount": 9415 } ] } ],
  // with include_charges
  "filtered": { "sum": 27973.68, "count": 24, "truncated": false },
  "charges": [
    { "purchase_date": "2026-09-03", "billing_date": "2026-10-15", "merchant": "…",
      "category_name": "…", "amount": -4200,
      "installment": { "number": 2, "of": 6 }, "is_refund": false } ] }
14

משימה למנהל התזרים

haki_create_taskקטן
מה קיים
קוד הסקיל create_task, skills.registry.js:2185. מקבל description ו-original_user_message. קורא ל-handleCreateTaskFromRequest (chat.logic.js:2254), שיוצר אירוע דרך EventService.createEventFromMessage (EventService.js:1947): event_type: 'MESSAGE', status: 'WAITING_FOR_HANDLE', due_date = עכשיו.
איפה מחובר
קוד create_task המקורי מחובר בפלואו 56 ו-57 (יועץ), ולא ב-58 ו-59 (בעל העסק). הוא נשאר כמו שהוא. את העותק אני מחבר ל-57 ול-59.
למי משויך
קוד assignee: company.hk_operator_user_id. במודל החברה יש ארבעה שדות של אנשי צוות: consultant_operator_user_id, hk_consultant_operator_user_id, hk_operator_user_id, ops_manager_id (company.models.js:120-133).
שאלה אליך
איזה מהשדות הוא מנהל התזרים? אם זה לא hk_operator_user_id, צריך לשנות את השיוך. ומה קורה כשהשדה ריק בחברה.
חסר: בדיקות
קוד ה-handler לא בודק is_test. סקילים אחרים שמבצעים פעולה כן בודקים (:912, :1138, :2462, :2521). היום שאלת בדיקה תפתח משימה אמיתית אצל הצוות, ולכן אני לא יכול לבדוק את הסקיל הזה בכלל.
נדרש
  • ב-is_test: לא ליצור אירוע, ולהחזיר {created: false, test: true} עם התוכן שהיה נוצר.
  • פרמטר title קצר, בנוסף לתיאור.
  • סימון מקור באירוע (metadata.source: 'ai_chat', ומזהה השיחה), כדי שהצוות יידע שהמשימה נפתחה מהעוזר, ויוכל לראות את השיחה.
  • מניעת כפילות: אם נפתחה משימה זהה לאותה חברה בדקות האחרונות, להחזיר אותה ולא לפתוח חדשה. המודל עלול לקרוא לכלי פעמיים באותה תשובה.
  • בפלט: created, מזהה, שם האחראי (לא רק המזהה שלו), וסטטוס בעברית.
  • כשל: {error: "TASK_NOT_CREATED", reason}. היום חריגה נזרקת מה-handler בלי טיפול.
עוד פרט
קוד ה-handler מעביר user_message_model, שמגיע מהודעת וואטסאפ. השערה בצ'אט של הממשק הוא ריק, ואז המשימה לא מקושרת להודעה. הקוד לא נופל על זה (if (userMessageModel && …)), אבל הקישור חסר.
מה אני עושה
כלל בהנחיות: האקי לא פותח משימה בלי שהלקוח ביקש או אישר במפורש. הוא מציע, מנסח את המשימה, ופותח רק אחרי "כן". אחרי הפתיחה הוא אומר ללקוח מה נפתח ולמי.
שאלה לאייל
האם האקי מציע לפתוח משימה גם ביוזמתו, למשל כשהוא לא יודע לענות, או רק כשהלקוח מבקש.
// in
{ "title": "דחיית תשלום לספק", "description": "…", "original_user_message": "…" }

// out
{ "created": true, "id": 48211, "status_he": "ממתין לטיפול",
  "assignee_name": "…", "created_at": "2026-09-29T14:05:00+03:00" }
15

המלצת תשלום לספק

flow 61 (stg) · flow 68 (prod sandbox)בינוני
מה נעשה
העתקתי את פלואו 61 מסטייג'ינג לפרוד כפלואו 68, בלי נקודת כניסה, וחיברתי אותו להאקי בסביבת החול 59 ככלי payment_recommendation. העותק המקורי שמור ב-hk/ai/sandbox/68_as_copied_from_stg.json.
מה עובד
נמדד חברה 4, שיחה של שלוש הודעות: השלבים רצים לפי הסדר (אישור תזרים, אמצעי תשלום, המלצה), האקי מעביר את הפרטים משלב לשלב, והחריגה נמדדת מול המסגרת.
מה היה שגוי
נמדד הפלואו בדק חריגה רק ביום התשלום. את 30 הימים שאחריו הוא בדק בלי להפחית את התשלום (cashflow_after.deviation.first_deviation_date). בחברה 4: תשלום של 50,000 ₪ היום קיבל "אפשר לשלם, לא צפויה חריגה", בזמן שהנקודה הנמוכה ב-22.10 היא 51,174- ואחרי התשלום 101,174-, מול מסגרת של 100,000-. גם max_payable_without_breach חזר 69,012 במקום 48,826.
מה תיקנתי
בהנחיות של הסוכן בפלואו 68: החריגה אחרי התשלום נבדקת לכל יום אחרי הפחתת הסכום, והסכום המרבי מחושב לפי הנקודה הנמוכה בכל התקופה. נמדד אחרי התיקון: חריגה ב-22.10 בסך 1,174 ₪, סכום מרבי 48,826 ₪, והמלצה לתשלום חלקי.
מה נשאר
  • החישוב נעשה במודל, לא בקוד. נמדד באותה שאלה, בשתי הרצות, balance_before חזר פעם 30,987- (כולל נגררת של 5,000) ופעם 25,987- (בלי). נדרש: סקיל שמקבל תאריך וסכום ומחזיר את facts מחושב, והסוכן רק מנסח.
  • בדיקת הכפילות חלקית. קוד cashflow_analyze מחזיר רק את 5 התנועות הגדולות לכל כיוון ואת הנגררות, ולכן תשלום דומה לאותו ספק שאינו בין הגדולות לא יזוהה. תלוי במשימה 2.
  • זמן. נמדד 17 עד 51 שניות לכל שלב, ושיחה מלאה היא 2 עד 4 שלבים.
  • suggested_date ו-similar_payment חוזרים כמחרוזת "null" ולא כערך ריק.
ההמלצה
סקיל אחד שמחשב בקוד, haki_payment_check, והסוכן רק מנסח. הפלואו נשאר, עם שלבי הבירור שלו. מה שעובר לקוד הוא כל מה שהוא חשבון.
הלוגיקה
  • שולף את התחזית המאוחדת מהיום ועד 30 יום אחרי מועד התשלום, מ-getForecast, עם כל התנועות.
  • מפחית את הסכום מהיתרה של כל יום ממועד התשלום והלאה, ובודק כל יום מול המסגרת.
  • צ'ק נספר במועד הפירעון ולא במועד התשלום.
  • מחפש בתחזית תנועות קיימות לאותו מוטב, לפי שם, בכל התנועות ולא רק בגדולות.
  • "למתי אפשר לשלם": היום הראשון שבו התשלום משאיר את כל הימים שאחריו בתוך המסגרת. אם אין יום כזה בטווח, מחזיר כמה חסר.
  • מסמן אם המסקנה נשענת על הכנסות שהן הערכה ולא תנועה רשומה.
שלבים
היום יש עד ארבעה שלבי בירור, וכל שלב הוא 17 עד 51 שניות. ההצעה: הסקיל מחזיר בקריאה אחת גם את התנועות לאישור וגם את התנועות הדומות, והסוכן שואל את הלקוח שאלה אחת מרוכזת. כשהלקוח נתן סכום, תאריך ואמצעי תשלום כבר בשאלה הראשונה, נשאר שלב בירור אחד.
// in
{ "amount": 100000, "payment_date": "2026-09-30", "payee_name": "בית הבשר",
  "payment_method": "check", "clearing_date": "2026-10-15",
  "replaces_transaction_id": null }     // set when the customer says it is the same payment

// out
{ "effective_date": "2026-10-15",
  "balance_before": -175734, "balance_after": -275734, "credit_limit": -100000,
  "breach_on_date": true,
  "first_breach_after": { "date": "2026-10-15", "over_by": 175734 },
  "baseline_already_in_breach": true, "baseline_first_breach": "2026-09-30",
  "max_payable_without_breach": 0,
  "earliest_safe_date": null, "shortfall_for_requested_date": 175734,
  "similar_transactions": [ { "id": "…", "date": "2026-09-30", "description": "בית הבשר", "amount": 80000 } ],
  "transactions_to_confirm": [ … up to 10 largest until the payment date … ],
  "relies_on_estimates": { "income_estimate_until_date": 0 },
  "account_alerts": [ … ],
  "period_checked": { "from": "2026-09-29", "to": "2026-11-14" } }

לעידו: נתונים חלקיים בקריאה עם ימים

הנושא הזה בשירות הסנכרון של ביזיבוקס, ולכן הוא אצל עידו ולא אצל עומרי. הוא לא חלק מ-15 המשימות. הוא קודם להן בחשיבות: הוא גורם להאקי לתת מספר שגוי שנראה נכון, והוא קיים גם בפלואים החיים.

עדכון 30.09. קוד בקומיט של עידו מ-29.09 בסטייג' (07e7e198, לוח #433) המנגנון הזה נכתב מחדש: ensureRawSnapshots כבר לא בודק "קיים snapshot לחודש", אלא בוחר לכל חשבון וחודש את ה-snapshot העדכני, ורענון חלקי מתמזג לתוך החודש במקום להחליף אותו (history-refresh-policy.js, mergeCoveredTransactions). השערה זה אמור לסגור את הבעיה שתועדה כאן. עוד לא נפרס לפרוד (#435). אחרי הפריסה אחזור על אותה שאלה בחברות 4 ו-70 ואשווה למספר של החודש השלם.

snapshot חודשי שמכיל רק חלק מהחודש

bizibox-sync-service
החודש הנוכחי עם ימים
נמדד 29.09, get_monthly_report עם ימים בתוך ספטמבר מחזיר נתונים חלקיים או ריקים. אותו חודש בלי ימים מחזיר את המספר המלא:
חברהטווחהכנסות, עם ימיםהכנסות, בלי ימיםימים שחזרו
701.9 עד 29.9181,597.38781,114.4522, 23, 24, 25 בלבד
41.9 עד 29.9ריק163,068.01אף יום
41.9 עד 28.9ריק163,068.01אף יום
זה לא קשור ליום הנוכחי: גם טווח שמסתיים אתמול חזר ריק. באוגוסט הקריאה עם ימים החזירה נתונים (חברה 4: ימים 2 עד 25). לא בדקתי אם גם שם חסרים ימים.
למה זה מסוכן
בחברה 70 האקי ענה בביטחון שההכנסות עד היום הן 181,597 ₪, ושהן נמוכות ב-564,972 ₪ מהחודש הקודם. התשובה נראית תקינה, עם מקור ועם שני טווחים, והיא שגויה. אותה בעיה צפויה בכל שאלה עם ימים בחודש הנוכחי: "בשבוע שעבר", "אתמול", "מתחילת החודש". זה נוגע גם לחיפוש (פלואו 36), שקורא מאותו מקור.
איפה בקוד
קוד בשירות הסנכרון, התנועות נשמרות כ-snapshot לפי חברה, חודש והיקף חשבונות:
  • sync-run.service.js:1774: הריצה שומרת ל-snapshot רק את התנועות שבתוך טווח התאריכים שהתבקש (filterTransactionsForRun), ורושמת אותו ב-dateFrom ו-dateTill.
  • sync-run.service.js:1822: findOrCreate לפי חברה, חודש והיקף. אם כבר יש snapshot לחודש והתוכן שונה, הוא מוחלף בתוכן של הטווח החדש.
  • cashflow-report.service.js:2053 (ensureRawSnapshots): בודק רק שקיים snapshot לכל חודש בטווח (hasAllMonths). הוא לא בודק שה-dateFrom וה-dateTill של ה-snapshot מכסים את הטווח שהתבקש עכשיו.
התוצאה: בקשה על חלק מחודש יוצרת snapshot חלקי, וכל בקשה אחריה על אותו חודש מקבלת רק את החלק הזה.
התאמה לממצא
נמדד ב-28.09 שאלתי על חברה 70 "תראה לי את כל התנועות בשבוע שעבר", טווח 21.9 עד 27.9. ב-29.09 הבקשה ל-1.9 עד 29.9 החזירה את הימים 22 עד 25 בלבד, כולם בתוך הטווח של אתמול.
מה לא אימתתי
השערה שהסקיל עובר בפרוד דרך שירות הסנכרון ולא דרך המסלול הישן ב-CompanyService.js:4702, שקורא ישר מביזיבוקס בלי snapshot. ההכרעה ב-shouldUseBiziboxSyncCashflowService (CompanyService.js:89) תלויה במשתנה סביבה ובמשתמש. לא ראיתי את שורות ה-snapshot עצמן. את הריק בחברה 4 לא הסברתי עד הסוף: ייתכן שריצה אחרת החליפה את ה-snapshot בטווח שכולו עתיד.
תיקון אפשרי
ב-ensureRawSnapshots: להתייחס ל-snapshot כחסר כשה-dateFromMs שלו מאוחר מתחילת הטווח המבוקש או שה-dateTillMs שלו מוקדם מסופו. או לסנכרן תמיד חודשים שלמים, בלי קשר לטווח שהתבקש.
מה נעשה בינתיים
בסביבת החול האקי לא קורא לכלי עם ימים בתוך החודש הנוכחי. להשוואה "עד היום מול אותו תאריך" הוא מציג חודש נוכחי חלקי מול חודש קודם מלא, ואומר זאת. זו לא התשובה שאייל רוצה, אבל היא נכונה.

שאלות פתוחות אליך

#שאלהמשימה
1התיקון לסינון לפי חשבון ב-cashflow_analyze קיים בקוד מ-17.09 (קומיט fcd3f43, ההערה מעל ה-handler). בבדיקות שלי בפרוד ב-28.09 הכלי עדיין החזיר את המספר המאוחד, 6 מתוך 6. הגרסה עלתה לפרוד?2
2איך מזהים תנועת הערכה בוודאות, ומה ההבדל בין "תקציב" ל"צפי"?3
3הוצאות אוקטובר שונות בין future_data לתחזית היומית: חברה 70, 596,002 מול 513,505. חברה 432, 439,157 מול 486,108. ההכנסות זהות ב-3 מ-3 חברות. מה הסיבה?3, 6
4אפשר להגדיר בפלואו פרמטר קבוע לכלי שהמודל לא רואה (audience)?5
5מה פלואו 36 מחזיר במצב עתיד כשהנושא לא נמצא ב-Category_Tags?6
6נפח ומשך של פלואו 36, ושלושת העותקים של ה-trace9, 12
7איזה שדה במודל החברה הוא מנהל התזרים?14
8get_monthly_report עם ימים בתוך החודש הנוכחי מחזיר נתונים חלקיים (חברה 70: 4 ימים מתוך 29) או ריקים (חברה 4). למה, והאם זה קורה גם בחודשים קודמים?6

מה אני עושה בצד של הפלואו

מהתלוי בך?
להוריד את cashflow_report מהאקי ב-57 וב-59, ולעדכן את ההנחיות. בוצע ב-59.לא
תיאור חד לכל כלי: מתי כן ומתי לאלא
כללים: חודשים שלמים בלי ימים. סכום של משהו מסוים הולך לחיפוש, תמונה כוללת לדוח החודשי.לא
קיצור ההנחיות. היום 23,634 תווים בסביבת החול, מול 13,440 בפלואו החי.לא
ניסוח ללקוח: "כבר רשום" מול "הערכה"כן, משימה 3
חיבור get_company_credit_cards להאקי, עם תיאור וגבול מול התחזיתכן, משימה 13
חיבור create_task לפלואו של בעל העסק, עם כלל האישורכן, משימה 14. לא אחבר לפני שיש הגנת is_test.
עדכון ההצהרות של הכלים אחרי כל משימהכן

כל השינויים שלי נעשים רק בעותקים: 57, 59 ו-68. את 56, 58, 35 ו-36 אני לא עורך.

חריג אחד שכבר קיים. ב-28.09, לפני הכלל הזה, שיניתי בפלואים החיים 56 ו-58 דבר אחד: עקיפה של נתיב השאלות המוכנות (#418). גיבוי מלא של שניהם שמור ב-hk/ai/sandbox/56_before_418_2026-09-28.json וב-58_before_418_2026-09-28.json, ואפשר להחזיר אותם למצב הקודם בקריאה אחת. אייל יחליט אם להחזיר.

כבר בוצע

מהמצבמה אבדוק אחרי הפריסה
בוצע מסגרת פנויה הפוכה, #411סטייג'ינג 28.09"כמה מסגרת פנויה יש לי?" על 4, 70, 432
בוצע פרופיל לפי קהל, #412סטייג'ינג 28.09, עמודת chat_visible_roles"מה כתוב עליי בזיכרון שלכם?" על 5 חברות מחזיר אפס ציטוטים
בוצע נטרול השאלות המוכנות, #418בהגדרת הפלואו, בלי קוד. נעשה גם ב-56 וב-58 החיים."כמה הכנסתי חודש קודם" עובר דרך האקי
קיים עיגון נתונים, שלב א'לוג בלבדמשימה 11

מה נדחה

רשימת המשימות והבקשות הפתוחות של הלקוח, סימולציית "מה אם אשלם", ושאלות מקצועיות על הענף. אייל יחליט עליהם אחרי הגרסה הזו.

איך כל משימה נבדקת

חמש חברות קבועות (4, 70, 81, 111, 432), אותן שאלות מבנק השאלות, קודם על סביבת החול ואז על הפלואו החי. כל מספר בתשובה מושווה למה שהכלי החזיר ולמה שהדשבורד מציג. הניתוח של בחירת הכלים: hk/ai/tool-usage-analysis.md. המחקר על קוד השרת: hk/ai/server-grounding-skills.md.

מקור: קריאה של קוד השרת (hk-server, ענף stg, קומיט אחרון b417c3f מ-27.09.2026), בלי שום שינוי בקוד. מדידות מפרוד: 806 תשובות בבדיקות של 28 ו-29.09, וקריאות API ישירות ב-29.09.