ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s

This commit is contained in:
2026-08-20 13:12:50 +00:00
commit b119135836
10275 changed files with 3284984 additions and 0 deletions
@@ -0,0 +1,119 @@
"""Case study: Banking / transactions.
Architectural pattern demonstrated: **cross-object balance invariant**.
A transaction's validity depends on the sender account's current balance --
the validator must read related state (the sender account) and compare to the
proposed change. This pattern doesn't fit single-table CHECK constraints; it
requires a runtime validator that reads cross-object state at write time.
Object types: account, transaction, audit_log
Key invariants:
- sender_account.balance >= amount before transaction commits
- account ownership: only the account's owner can initiate transfers
- transactions are immutable after creation (no UPDATE)
- balance updates are reactions, not direct writes (single source of truth)
"""
from __future__ import annotations
from pedo.core.models import (
AccessContext, DataObject, ObjectType, Operation,
PermissionRule, PrivilegeType, ReactionDeclaration,
Relationship, RelationshipAction,
)
from pedo.core.store import ObjectStore
def validate_transaction_balance(proposed, existing, accessor, store):
"""Sender account must have sufficient balance for the transfer."""
if existing is not None:
return "Transactions are immutable; cannot UPDATE"
sender_id = proposed.content.get("sender_account_id")
amount = proposed.content.get("amount", 0)
if sender_id is None or amount is None:
return "sender_account_id and amount are required"
if amount <= 0:
return f"Transfer amount must be positive, got {amount}"
sender = store.raw_read(sender_id)
if sender is None:
return f"Sender account {sender_id} not found"
if sender.type_name != "account":
return f"sender_account_id must reference an account, not {sender.type_name}"
if sender.content.get("balance", 0) < amount:
return (f"Insufficient balance: account has "
f"{sender.content.get('balance', 0)}, transfer requires {amount}")
return True
def validate_transaction_recipient_exists(proposed, existing, accessor, store):
"""Recipient account must exist and accept transfers."""
if existing is not None:
return True
recipient_id = proposed.content.get("recipient_account_id")
if not recipient_id:
return "recipient_account_id is required"
recipient = store.raw_read(recipient_id)
if recipient is None or recipient.type_name != "account":
return f"Recipient account {recipient_id} not found"
if recipient.content.get("status") == "frozen":
return "Recipient account is frozen"
return True
def apply_transaction(event, store):
"""Reaction: when a transaction commits, debit sender and credit recipient.
The handler did not have to encode this -- the schema declares it."""
sys_ctx = AccessContext(user_id="system", role="system", org_id=event["object_org"])
sender_id = event["object_content"]["sender_account_id"]
recipient_id = event["object_content"]["recipient_account_id"]
amount = event["object_content"]["amount"]
sender = store.raw_read(sender_id)
if sender is not None:
store.update(sender_id,
{"balance": sender.content.get("balance", 0) - amount},
sys_ctx, _reaction_depth=event["depth"])
recipient = store.raw_read(recipient_id)
if recipient is not None:
store.update(recipient_id,
{"balance": recipient.content.get("balance", 0) + amount},
sys_ctx, _reaction_depth=event["depth"])
def register_banking_types(store: ObjectStore) -> None:
store.register_reaction_handler("apply_transaction", apply_transaction)
# Account: owner-only management; balance is updated only by reactions.
store.register_type(ObjectType(
name="account",
fields={"holder_name": "str", "balance": "int", "status": "str"},
permission_rules=[
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"is_owner": True}),
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"role": "system"}),
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"role": "auditor"}),
PermissionRule(Operation.ACCEPT, PrivilegeType.INSERT, {"role": "admin"}),
# Balance writes happen via the apply_transaction reaction (system role)
PermissionRule(Operation.ACCEPT, PrivilegeType.WRITE, {"role": "system"}),
PermissionRule(Operation.ACCEPT, PrivilegeType.WRITE, {"role": "admin"}),
],
default_policy=Operation.DENY,
))
# Transaction: immutable after create; validators run cross-object checks.
store.register_type(ObjectType(
name="transaction",
fields={"sender_account_id": "str", "recipient_account_id": "str",
"amount": "int", "subject": "str"},
permission_rules=[
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"is_owner": True}),
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"role": "auditor"}),
PermissionRule(Operation.ACCEPT, PrivilegeType.READ, {"role": "system"}),
PermissionRule(Operation.ACCEPT, PrivilegeType.INSERT, {}), # any authenticated user
# No WRITE / UPDATE / DELETE rules: transactions are immutable.
],
validators=[validate_transaction_balance,
validate_transaction_recipient_exists],
reactions=[
ReactionDeclaration(event="after_create", handler="apply_transaction"),
],
default_policy=Operation.DENY,
))