AI 资讯
Find the cheapest day to fly with a Google Flights price tracker (Python + n8n)
Google Flights has a date grid with a fare for every departure day, and a "track prices" toggle that emails you when its pick of dates moves. Both are fine for one trip. Neither gives you the table: every day, the fare, the airline and stops behind it, in rows you can sort, keep and put a threshold on. If your dates are flexible and you want the cheapest day to fly as data — or airfare price tracking that runs every morning — you need rows. This is how to get one row per departure day from Google Flights as JSON, with no API key (there is no public Google Flights API), and how to turn it into a flight price alert. 1. One request, one row per day The Flight Price Tracker on Apify takes routes, a first departure day and a window length. For each day it searches Google Flights, keeps that day's cheapest itinerary and ranks the days. A 30-day window on one route is at most 30 fare rows plus a free status row. curl -X POST "https://api.apify.com/v2/acts/kestrel~flight-price-tracker/run-sync-get-dataset-items?token= $APIFY_TOKEN " \ -H "Content-Type: application/json" \ -d '{"routes": ["LIS-LHR"], "departDate": "2026-10-05", "days": 30, "adults": 1, "currency": "USD", "market": "us"}' A fare row: { "type" : "fare" , "route" : "LIS-LHR" , "trip" : "one_way" , "depart_date" : "2026-10-05" , "return_date" : null , "seat" : "economy" , "adults" : 1 , "currency" : "USD" , "price" : 127 , "price_display" : "127 US dollars" , "airline" : "Tap Air Portugal" , "stops" : 0 , "depart_time" : "8:00 PM" , "arrive_time" : "10:55 PM" , "duration" : "2 hr 55 min" , "duration_minutes" : 175 , "layovers" : null , "co2_kg" : 123 , "itineraries_seen" : 12 , "cheapest_in_window" : true , "rank_in_window" : 1 , "google_url" : "https://www.google.com/travel/flights?tfs=..." , "fetched_at" : "2026-08-29T06:25:14+00:00" } cheapest_in_window is true on exactly one day per route; rank_in_window orders the rest. The free status row repeats the headline as cheapest and cheapest_date , with days_searc
AI 资讯
okf-guard: A Security Layer for Open Knowledge Format (OKF) Pipelines
Catching Prompt Injection Before It Enters a Trusted Knowledge Base AI agents increasingly consume knowledge from sources they did not author and cannot independently verify: a PDF policy document, a scraped web page, a spreadsheet exported from another team's system. The prevailing approach — extract the text, write it into a knowledge base or context window, let the agent treat it as fact — has an underexamined weakness. Extraction tools capture everything present in a source document, including content a human reviewer would never see. The Mechanism Several ordinary, well-documented features of common file formats allow text to be present in a document while remaining invisible to anyone reading it normally: A PDF can render text in a rendering mode that instructs viewers not to display it, or set its fill color identical to the page background. A Word document has an explicit "hidden" attribute on any run of text, independent of color or size. A PowerPoint file's speaker notes are parsed by most extraction tools but never appear to an audience watching the presentation. A spreadsheet can mark entire rows, columns, or sheets as hidden, or attach a comment to a cell that is invisible unless hovered. An HTML page can hide an element from a browser's rendering entirely via a handful of standard CSS properties. None of these are obscure edge cases. They are common, legitimate formatting features, used constantly for entirely benign reasons — a hidden helper column in a spreadsheet, a private note to a presenter, draft text a Word user hid rather than deleted. The problem is not that these features exist; it is that an extraction pipeline has no reason to distinguish "this text is legitimate content" from "this text was deliberately hidden" unless something is specifically checking for the difference. Why This Matters for AI Pipelines Specifically If an attacker can place text anywhere in this chain — inside a PDF a company will later ingest, inside a web page a scrap
AI 资讯
LeetCode ~ first 30 Hard problems, with solutions
Pulled live from leetcode.com/problemset/?difficulty=Hard on 29 Aug 2026 (895 hard problems in the Algorithms list). "First 30" = the 30 lowest problem numbers. Everything below is Python 3 . How to use this Open the problem on LeetCode and make sure the language selector says Python3 . Select all the text in the code editor and delete it. Paste the block below in its place — each block already contains the class Solution signature LeetCode generated for that problem, plus any commented-out ListNode / TreeNode header. Press Submit . Do not add import statements or redefine ListNode / TreeNode — LeetCode injects typing.List , typing.Optional , heapq , math.gcd and the node classes automatically. The blocks are written to rely on exactly that. Verification Every solution was executed locally against an independent brute-force reference on randomised and edge-case inputs ( 4,637 assertions, all passing ), then stress-tested at each problem's documented maximum input size ( 31/31 within budget ). Two real defects were found and fixed during that pass — see the notes on #127 and #149. 4. Median of Two Sorted Arrays https://leetcode.com/problems/median-of-two-sorted-arrays/ Approach. Binary search on the cut position of the shorter array. O(log(min(m,n))) , O(1) space. Constraints (from the problem page). nums1.length == m nums2.length == n 0 <= m <= 1000 0 <= n <= 1000 1 <= m + n <= 2000 -10 6 <= nums1[i], nums2[i] <= 10 6 class Solution : def findMedianSortedArrays ( self , nums1 : List [ int ], nums2 : List [ int ]) -> float : # Binary search on the shorter array's cut position. O(log(min(m, n))). if len ( nums1 ) > len ( nums2 ): nums1 , nums2 = nums2 , nums1 m , n = len ( nums1 ), len ( nums2 ) lo , hi = 0 , m total = ( m + n + 1 ) // 2 while lo <= hi : i = ( lo + hi ) // 2 # take i elements from nums1 j = total - i # take j elements from nums2 l1 = nums1 [ i - 1 ] if i > 0 else float ( ' -inf ' ) r1 = nums1 [ i ] if i < m else float ( ' inf ' ) l2 = nums2 [ j - 1 ]
AI 资讯
Building CareLoop: an autonomous clinical-triage agent where rules decide and AI explains
I created this content for the purposes of entering the All Things Agentic Hackathon. The problem that started it A doctor gets about eight minutes with a patient and, for anyone with a real history, forty pages of scattered records — lab reports, discharge notes, and pharmacy bills from three different clinics. So the history is effectively invisible at the exact moment it matters most. And when the visit ends, nothing follows up: the six-month course lapses at week five, the recheck never gets booked. I wanted to build an agent that closes that loop — one that reads the mess, decides urgency in a way a clinician can actually trust, and handles the follow-up on its own. That became CareLoop , my entry for the All Things Agentic Hackathon (Taskmaster track), built on Gemini, the Google Agent Development Kit (ADK), Cloud Run, and Firestore. The one principle I wouldn't compromise on Rules decide, AI explains. The temptation with an LLM is to let it do everything — including deciding whether a chest-pain patient is urgent. I refused to do that. In CareLoop, a deterministic engine owns every clinical decision: a weighted symptom score plus a red-flag override sets the triage level and routing. It is fully auditable, and it returns byte-identical output on the same input every single time. The LLM's job is strictly language: Reading unstructured documents into a fixed schema — I call it "Gemini extracts, rules merge." Writing the structured result into a plain-language brief a clinician can skim in ten seconds. No language model is ever in the decision path. When a judge asks "why was this Critical?", the answer is a score breakdown they can inspect — not a model's say-so. That single decision shaped the whole architecture. What it actually does CareLoop runs the full loop end to end: Ingest & compact — it reads a patient's documents and merges them into one structured ledger: allergies, chronic conditions, active medications, and lab trends over time. Instead of pushin
AI 资讯
I Asked a Free Model the Same Question for 48 Hours. The Drift Was the Signal.
Most model benchmarks tell you how smart the model is on the first attempt, which is almost never the problem in production. The real problem is what happens on the 120th attempt, when the same kind of input shows up again and nobody is watching. I spent 48 hours running the same classification task against a free model on a free server, and the drift taught me more than accuracy ever did. The Setup I'd Run Again The workload was dull on purpose: ten support tickets, three labels, one prompt template. Every hour the job asked the model to classify one ticket and logged the raw output, so each ticket appeared about twelve times. It was not a benchmark of intelligence; it was a probe of stability, and stability is what automation actually needs. I ran the whole thing on MonkeyCode's free server option, using the free model access for inference, because a cheap long-running job is exactly the scenario that setup is for. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The rest is about what the probe caught, not about quotas or latency, so treat my numbers as one operator's field notes. The Probe Code (Steal This) A probe is only honest if it writes down everything, including the outputs you didn't ask for. The script below hashes every response, tries to parse a label, and appends one JSON line per run, so nothing interesting ever gets lost. import hashlib , json , time LOG_PATH = " drift.jsonl " LABELS = ( " bug " , " feature " , " question " ) def stable_hash ( text ): return hashlib . sha256 ( text . strip (). encode ()). hexdigest ()[: 12 ] def parse_label ( raw ): # Accepts JSON or plain prose; returns None when the format is unknown. try : return json . loads ( raw ). get ( " label " ) except json . JSONDecodeError : found = [ label for label in LABELS if label in raw ] return found [ 0 ] if found else None def record_run ( run_id , ticket_id , raw , expected ): entry = { " run " : run_id , " ticket " : ticket_id , " hash " : stabl
AI 资讯
Hotel price tracking with Google Hotels data: an API in 10 minutes (Python + n8n)
Google Hotels already compares every booking site for a hotel and a stay — Booking.com, Expedia, Agoda, Hotels.com and the hotel's own site. It has a "track prices" button too, but it emails you on its own terms, picks the sources, and keeps the history. If you want the numbers — for a trip, a rate parity check, or a price history chart — you need them as rows. This is how to get Google Hotels prices for exact dates as JSON, without a Google API key (there is no public Google Hotels API for reading prices; the official Hotel APIs are feeds for hotels sending prices to Google), and how to turn that into daily hotel price tracking. 1. One request, every booking site's rate The Google Hotels Prices Scraper on Apify takes a place search or a list of hotels, a stay, occupancy and currency, and returns three row types: hotel (lowest nightly rate + stay total), offer (each source's rate, free‑cancellation flag, deep link) and status . You pay per priced row; sold‑out hotels and empty searches are free. curl -X POST "https://api.apify.com/v2/acts/kestrel~google-hotels-prices/run-sync-get-dataset-items?token= $APIFY_TOKEN " \ -H "Content-Type: application/json" \ -d '{"queries": ["hotels in Lisbon"], "checkIn": "2026-10-03", "checkOut": "2026-10-06", "adults": 2, "currency": "USD", "maxHotels": 20}' A hotel row looks like this: { "type" : "hotel" , "name" : "The Central House Lisbon Baixa" , "check_in" : "2026-10-03" , "check_out" : "2026-10-06" , "nights" : 3 , "nightly" : 81.81 , "nightly_display" : "$82" , "total" : 245 , "stars" : 2 , "rating" : 4.3 , "reviews" : 727 , "deal" : "19% less than usual" , "entity_id" : "ChkIg-b2ismUj7M1Gg0vZy8xMWg3MThreGg1EAE" , "google_url" : "https://www.google.com/travel/hotels/entity/ChkI…" } and an offer row (with "includeOffers": true ): { "type" : "offer" , "name" : "Hyatt Regency Lisbon" , "source" : "Booking.com" , "official" : false , "nightly" : 569.35 , "total" : 1708.05 , "free_cancel" : true , "free_cancel_until" : "Oct 1" , "p
AI 资讯
Architectural Breakdown: Building Next-Gen Agentic Architectures: From Local RAG to Sandboxed Execut
Building Next-Gen Agentic Architectures: From Local RAG to Sandboxed Execution and BigQuery MCP The 3 AM production fire revealed a harsh truth: modern agentic systems often collapse under their own weight. A single agent processing 10K RAG queries OOM-killed an 8GB cloud instance. The culprit was not the workload but the infrastructure: @pinecone-client/vecdb with 47 transitive dependencies bloat memory with unquantized float32 embeddings. The solution was 200 lines of Python using sqlite3 , array , and heapq , with bounded queues and race condition resilience. This is the story of how we replaced dependency bloat with surgical precision. The Dependency Problem Agentic systems today face three critical bottlenecks: Vector Search : Libraries like faiss-cpu (12MB) combined with pg-vector (synchronous disk I/O) block the event loop, creating latency spikes. BigQuery : The @google-cloud/bigquery client (12MB) plus grpcio (5MB) leaks file descriptors, hitting Linux's default 1024 soft limit. Sandboxing : Docker containers consume 500MB+ per instance, making them impractical for memory-constrained environments. The root cause is always the same: unbounded resource consumption. 1M vectors at 768 dimensions in float32 consumes 3GB of memory. Synchronous I/O stalls the event loop. Unmanaged connections leak file descriptors. The Zero-Bloat RAG Engine The solution begins with a fundamental shift: replace heavy dependencies with lightweight, audited code. Our LocalRAG implementation demonstrates this approach: import sqlite3 import array import heapq import json import threading from typing import List , Tuple , Optional class LocalRAG : def __init__ ( self , db_path : str , dim : int = 768 , max_vectors : int = 1_000_000 ): self . dim = dim self . max_vectors = max_vectors self . lock = threading . Lock () self . conn = sqlite3 . connect ( db_path , isolation_level = None , check_same_thread = False ) # Enable WAL mode for concurrent reads/writes self . conn . execute ( " PR
AI 资讯
Build a Natural Language IVR with Telnyx Call Control and AI Inference
Nobody likes phone trees. "Press 1 for billing, press 2 for support." Miss an option? Start over. It is friction at its worst. The voice-ivr-with-agent-backend example replaces that with a natural language conversation. Callers just say what they need, and the app routes them to the right department. Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/voice-ivr-with-agent-backend What it builds A Python/Flask app that handles inbound calls with a conversational IVR: Inbound Call -> answer with Call Control -> look up menu config from KV -> LLM generates a dynamic greeting -> gather(speech) — caller says what they need -> LLM routes intent to a department -> transfer call The core primitives The app combines four Telnyx primitives: Call Control : answer() , speak() , gather_using_speech() , transfer() AI Inference : telnyx.ai.openai.chat.completions.create() for greetings and intent routing KV store : menu config per phone number (business name, departments, transfer numbers, keywords) Agent state machine : an IVRAgent class that tracks call state, turn count, and retry logic Dynamic greeting via LLM Instead of a hardcoded "Press 1 for billing," the app generates a conversational greeting from the KV config: def generate_dynamic_menu_prompt ( menu_config : dict ) -> str : departments = menu_config . get ( " departments " , []) dept_list = " \n " . join ( f " - { d [ ' name ' ] } : { d [ ' description ' ] } " for d in departments ) return ( f " You are an IVR assistant for { menu_config [ ' business_name ' ] } . " f " Available departments: \n { dept_list } \n\n " f " Greet the caller briefly and ask how you can help. " f " Keep it conversational and under 2 sentences. " ) The LLM generates the greeting through the OpenAI-compatible Telnyx Inference binding. If it fails, the app falls back to a static greeting from the KV config. Intent routing via LLM When the caller speaks, the transcription is passed to route_intent_with_llm . The LLM is instructed
AI 资讯
Self-Hosting vLLM on Cloud GPUs in 2026: Sub-180ms LLM Inference for Autonomous AI Agents (Full Production Guide)
TL;DR: Running high-frequency autonomous AI agent loops on commercial LLM APIs at scale is economically unsustainable and introduces unpredictable latency spikes. This production guide details how we deployed a self-hosted inference cluster using vLLM (v0.6+) , EAGLE-3 speculative decoding , PagedAttention v2 , and Automatic Prefix Caching (APC) on cloud GPUs (RunPod/Vast.ai), achieving a sub-180ms Time-To-First-Token (TTFT) , 118 tokens/sec throughput , and cutting inference costs by 45–74% . 1. The Economic & Latency Bottleneck of Agentic Loops When building 24/7 autonomous daemon agents , LangGraph multi-agent state machines , or LLM-driven NPC game loops , the computational profile differs fundamentally from human chatbot interactions: Massive Request Volume: A single complex agent decision cycle frequently executes 5 to 25 LLM calls across intent classification, tool schema validation, reflection loops, and output formatting. Repeated Prefix Redundancy: 80–90% of prompt tokens consist of identical system instructions, persona framing, and MCP (Model Context Protocol) tool definitions. Strict Latency Budgets: Real-time simulations and game loops cannot tolerate 800ms–1500ms commercial API network roundtrips. Commercial Closed APIs (GPT-4o / Claude 3.5 Sonnet) ├── Prefill: Paid per-token on every single cyclic call ├── Network Roundtrip: 250ms - 600ms latency overhead └── Cost at 50,000 daily agent iterations: $1,200 - $3,500 / month Self-Hosted vLLM Cluster (RTX 4090 / A100 on RunPod) ├── Automatic Prefix Caching (APC): Reuses KV-cache (120ms -> 12ms prefill) ├── Speculative Decoding (EAGLE-3): 2.1x generation throughput └── Fixed Infrastructure Cost: $245 - $480 / month (Flat, unlimited tokens) 2. Deep Dive: The vLLM Memory & Scheduling Architecture PagedAttention: Eliminating KV-Cache Fragmentation Standard PyTorch/HuggingFace transformer implementations allocate static KV-cache tensors sized for max_sequence_length . Because 95% of queries generate far fewer
开源项目
🔥 goldmansachs / gs-quant - Python toolkit for quantitative finance
GitHub热门项目 | Python toolkit for quantitative finance | Stars: 12,772 | 25 stars today | 语言: Python
开源项目
🔥 HKUDS / AI-Trader - "AI-Trader: 100% Fully-Automated Agent-Native Trading"
GitHub热门项目 | "AI-Trader: 100% Fully-Automated Agent-Native Trading" | Stars: 21,730 | 155 stars today | 语言: Python
开源项目
🔥 abi / screenshot-to-code - Drop in a screenshot and convert it to clean code (HTML/Tail
GitHub热门项目 | Drop in a screenshot and convert it to clean code (HTML/Tailwind/React/Vue) | Stars: 75,295 | 309 stars today | 语言: Python
AI 资讯
🤔 Windows + WSL2 + Ollama - which architecture should I use?
I’m setting up a local AI development environment on Windows + WSL2 and I’m trying to decide between two architectures. Option 1 — Ollama/Models on Windows WSL2 ┌───────────────────┐ │ Application │ │ ├── Python │ │ ├── .venv │ │ └── Source code │ └───────┬───────────┘ │ HTTP localhost:11434 │ ▼ Windows ┌───────────────┐ │ Ollama │ │ ↓ │ │ Models │ │ ↓ │ │ GPU │ └───────────────┘ Option 2 — Ollama/Models inside WSL2 WSL2 ┌─────────────────────────┐ │ Application │ │ ↓ │ │ Ollama │ │ ↓ │ │ Models │ └────────────┬────────────┘ │ GPU access │ ▼ Windows ┌─────────────────────────┐ │ GPU / Driver │ └─────────────────────────┘ My current setup is Option 1 , and it works: WSL2 can access the Windows Ollama API through localhost:11434. But I’m wondering if Option 2 is a better long-term architecture for local AI/LLM development. I’m especially interested in: 🚀 Performance 🎮 GPU utilization 🧠 Model management 💾 Disk usage 🔧 Setup and maintenance 🐧 Linux/ML tooling 🐳 Docker integration 🌐 Networking 📈 Future scalability If you use Ollama with Windows + WSL2, which architecture would you choose and why? And if you've actually used both setups, I'd especially like to hear about your experience. 👇 Option 1 or Option 2?
AI 资讯
A TEMP Distribution Setup for My Ripper App
I’ve been working on a desktop utility called Ripper, a Python + CustomTkinter app that downloads video and audio from supported sites (starting with YouTube). The app itself has been a bit rough to build and maintain — but distributing it has been the annoying part. GitHub won’t host my repository, let alone the EXE, due to there size and I don’t want to rely on sketchy file hosts or temporary mirrors. So I finally figured out a temporary setup that’s stable and easy for users to follow. This post explains the distribution workflow and why I’m using it. Why I’m Using this Approach The EXE and source code are too large to push to GitHub, even when the ffmpeg EXE is zipped, and one of my main goals is that I don't want the user to have to hassle with getting ffmpeg. So, I set up a public Google Drive folder where users can get the zipped EXE file and use the app right away. But I want to emphasize that there’s nothing malicious. Google Drive Hosts the EXE Google Drive ended up being the simplest reliable host. It gives me: A clean public link No ads No expiration No weird redirects Instant updates when I replace the file Here’s the current download link: Download Ripper (Google Drive) https://drive.google.com/file/d/1w6rMgCAcSEteAssXIGJmYHrtyPHY99tC/view This is the only official download source. GitHub Pages Hosts Everything Else Since GitHub Pages can host static content, I built a simple project page that contains: https://codebunny20.github.io/ The official download link Feature list Tech stack Build instructions Planned features Version notes Development updates This page is now the “home base” for Ripper. Any time I push a new version, I update the Google Drive file and update the GitHub Pages site with the new version info. It keeps everything centralized without relying on GitHub Releases. Why This Setup Works Better It’s not fancy — but it’s reliable. I can update the EXE instantly I can update the GitHub Pages site just as fast Users always have one clean,
开源项目
🔥 perixtar / Tech-OA-Interview-Questions - Daily updated list of Tech Company OAs and Interview Problem
GitHub热门项目 | Daily updated list of Tech Company OAs and Interview Problems. Save your time from finding them all over the internet. | Stars: 4,635 | 98 stars today | 语言: Python
AI 资讯
Speaker - Designing Systems That Contain Failure - CS Week Perú 2026
Designing Systems That Contain Failure — CS Week Perú 2026 On August 13, 2026, I had the opportunity to speak at CS Week Perú 2026 , an event organized by IEEE Computer Society student chapters across Peru. My session was: “Isolation and Trust Boundaries in Production: Designing Systems That Contain Failure” The talk explored how production systems can be designed to limit the impact of failures through explicit trust boundaries, architectural invariants, and evidence-based validation. The central idea was simple: The goal isn't to prevent every failure. The goal is to control its blast radius. Production systems fail. Requests overlap, processes crash, memory is exhausted, credentials can be compromised, and dependencies can become unavailable. Reliable engineering is not about assuming that none of these things will happen. It is about deciding what can be affected when they do . From Unit Tests to System Properties A green unit-test suite demonstrates that the tested units behave correctly under the conditions we defined. But it does not necessarily demonstrate that the system as a whole preserves its architectural properties under concurrency, multiple tenants, resource exhaustion, or real deployment conditions. A function can be correct in isolation while the system still violates an important invariant. That led to one of the central questions of the talk: What properties must never be violated? Trust Boundaries I used the concept of a Trust Boundary to make architectural assumptions explicit. For each boundary, we can ask three questions: What are we protecting? What is allowed to cross the boundary? What happens if the condition is violated? From there, we can define invariants : properties that the system must preserve under the conditions established by its design. In the architecture discussed during the session, three dimensions were particularly important: Context → Logical isolation Identity → Cryptographic isolation Execution → Physical/process isolat
AI 资讯
Your Free AI Server Will Fail Quietly. Five Gates to Make It Loud.
Your Free AI Server Will Fail Quietly. Five Gates to Make It Loud. The model can be innocent. The server cannot. Earlier this week I wrote a fail-closed checklist for AI-generated code. That list guards against the model writing something dangerous. This list guards against something duller: the server around it dying at 2 a.m. while the model stays online the whole time. Nobody sees that failure until a user does. The setup I am testing MonkeyCode for a small side build: a log-summarizing API. The project gives you free model access and a free server option, which is exactly the toy setup I like. Ten lines of app logic. Zero dollars. One honest problem: free infrastructure is someone else's best effort. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Before you judge, my plan was simple. I deliberately killed my own server to see where the stack would fail. Then I wrote gates that make each failure loud. The kill test Here is the failure sequence, reproduced on purpose. The server process died. No restart policy. Connections hit a dead socket. Nothing answered. The client had no timeout and waited forever. No health probe. No alert. No log line. Four hours later, the model was still happy. The server was still dead. The tool was still broken. The model was innocent the whole time. The harness was the guilty one. The problem was never intelligence. It was silence. So here are five gates, ordered from cheapest to most annoying. Gate 1: A kill switch that outlives the process A crash bug can take down your app. It can also take down your ability to disable the app. So the switch lives outside the app. KILL_FILE = " /tmp/disable-monkeycode " @app.post ( " /summarize " ) def summarize ( logs : str ): if os . path . exists ( KILL_FILE ): raise HTTPException ( 503 , " disabled by operator " ) ... Why a file and not a database row? Because the DB may be down when you need the switch most. A file survives restarts. You can touch it from cron.
AI 资讯
A tabbed form that silently refused to submit — required fields hidden behind another tab
Background The site edit modal kept accumulating fields — site name, category, SSH connection details, WordPress install location — until editing anything meant scrolling up and down a single long form to find the right field. To clean this up, we split it into three tabs: "Registration info," "SSH," and "WordPress info." That change broke form submission itself, in a way that was hard to spot at first. What tabbing broke The tab implementation itself is straightforward. Each tab's fields live in a <div class="site-tab-content" data-tab="..."> , and CSS toggles which one is visible. .site-tab-content { display : none ; } .site-tab-content.active { display : block ; } An inactive tab is hidden with display: none . Nothing unusual so far, and visually it worked fine. The problem showed up when a required field sat in a tab that was not currently active, and the user left it empty while saving from a different tab. Clicking the save button did nothing . No error message appeared. The form just looked stuck. Root cause: a browser cannot report an error on a field it cannot show HTML5 form validation works by having the browser automatically block the submit event whenever a constrained field (like required ) fails, then focusing that field and showing its standard validation bubble (equivalent to calling reportValidity() ). Note: reportValidity() is a method from the HTML5 Constraint Validation API. It checks whether a form element's value satisfies its constraints (required, pattern, etc.) and, if not, displays the browser's standard error bubble. But when the failing field sits inside a tab hidden with display: none , the browser has nowhere to anchor that error bubble. It still faithfully blocks the submit — but it cannot visualize the error, so it simply stops without any visible feedback. From the user's side, this looks exactly like a button that does not respond. Before tabbing, every field lived on the same screen, so this never surfaced. Introducing tabs — a UI
AI 资讯
A LongMemEval-S number you can reproduce
We held off on posting a benchmark for a long time. Not because we didn't have runs - because most memory benchmarks you read are a number with no way to check it. A blog says "X%", and you have no idea what reader answered the questions, what judge scored them, how much context the retriever was allowed to feed, or whether an LLM quietly did the hard part inside the "memory" layer. So the number tells you almost nothing about the memory system. Here is one we're comfortable standing behind, because you can run it yourself. The result On LongMemEval-S , the full 500-question set, Engrava 0.6.0 scored 81.6% micro in August 2026 - 81.76% averaged across the six question categories. The run uses the canonical LongMemEval scorer (pinned to a known upstream commit), the standard gpt-4o-2024-08-06 reader and judge over the OpenAI API, and a top_k of 20 retrieved turns. Nothing about the reader, the prompt, or the scorer is ours; the only thing we swapped in is the memory. It is compared against the previous release: 0.5.0, run in July 2026, scored 82.4% micro / 82.58% macro on the same 500 questions, same reader, same judge, same scorer, same top_k . Both rows are on the leaderboard, both verified , and both ship their reproduction artifacts. We are leading with 0.6.0 because that is the version this post is about; the older row stays because removing it when the number goes down is exactly the move that makes benchmark pages worthless. 0.5.0 (2026-07-10) 0.6.0 (2026-08-11) micro 82.4% 81.6% macro 82.58% 81.76% n 500 500 Both figures are dated on purpose. This post is a record of two specific runs, not a running scoreboard; the current table, whatever version is newest when you read this, lives on the Engrava benchmarks page . The run also has no LLM in the memory pipeline. Ingestion and retrieval are deterministic - hybrid search over a typed graph, no model doing extraction, summarization, or re-ranking behind the curtain. In the benchmark's own terms this is a Group A
AI 资讯
Build an AI Shipment Agent with SMS, Voice, and Telnyx Inference
Most package tracking flows make the customer do the work. You get a tracking number. You open a page. You refresh it. Maybe you get a generic text that says the package is out for delivery. If you need to ask a real question, you usually end up somewhere else entirely. I wanted to build the opposite shape: what if the package itself had an agent? The shipment-agent example is a Python and Flask app that treats a shipment as a durable AI entity. It can send proactive SMS updates, understand customer replies with Telnyx AI Inference, and answer inbound calls with shipment context. Code: https://github.com/team-telnyx/telnyx-code-examples/tree/main/shipment-agent What it builds The app centers around a ShipmentAgent . The agent owns: shipment status carrier and tracking context customer phone number interaction history messaging and voice behavior Instead of a stateless chatbot waiting in a web page, the agent lives alongside the shipment lifecycle. Carrier update -> Flask webhook -> ShipmentAgent updates state -> SMS customer Customer SMS reply -> Telnyx Messaging webhook -> AI Inference response -> SMS reply Customer phone call -> Telnyx Call Control -> ShipmentAgent answers with context Why this is useful Shipment status is not just data. It is a customer communication problem. People want to know: Is my package delayed? Can I leave delivery instructions? Did it already arrive? Who do I call if something looks wrong? Traditional tracking pages are good at showing status, but not at handling conversation. This example shows how to turn the shipment into a small communications agent that can respond across SMS and voice. The main flow When a carrier status changes, the app receives a webhook. For example: out_for_delivery delayed delivered The ShipmentAgent updates its internal state and sends a message to the customer through Telnyx Messaging. If the customer replies, the app passes the message and shipment context to Telnyx AI Inference. That lets the response incl