everything-gemini 1.1.1 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
- package/.github/ISSUE_TEMPLATE/subagent_proposal.md +29 -0
- package/.github/workflows/ci.yml +72 -1
- package/.github/workflows/release.yml +17 -2
- package/.vscode/extensions.json +8 -0
- package/.vscode/settings.json +3 -0
- package/CHANGELOG.md +167 -0
- package/CONTRIBUTING.md +85 -4
- package/README.md +139 -18
- package/SECURITY.md +38 -0
- package/action.yml +35 -0
- package/agents/browser-qa.md +1 -1
- package/agents/database-migrator.md +26 -0
- package/agents/documentation-writer.md +27 -0
- package/agents/incident-responder.md +34 -0
- package/agents/performance-tuner.md +27 -0
- package/agents/release-engineer.md +34 -0
- package/bin/everything-gemini +1550 -86
- package/docs/COMMUNITY_SUBMISSIONS.md +88 -0
- package/docs/LAUNCH_KIT.md +148 -22
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +401 -37
- package/docs/launch-kit.md +163 -0
- package/examples/cli-workflows/README.md +45 -0
- package/examples/cli-workflows/demo_workflow.sh +39 -0
- package/examples/python-sdk/README.md +28 -5
- package/examples/python-sdk/documentation_audit_pipeline.py +83 -0
- package/examples/python-sdk/incident_triage_pipeline.py +170 -0
- package/examples/python-sdk/multi_agent_pipeline.py +95 -0
- package/examples/python-sdk/release_readiness_audit.py +144 -0
- package/hooks/secret-scrubber/hooks.json +16 -0
- package/hooks/secret-scrubber/scripts/scrub-secrets.sh +62 -0
- package/mcp/README.md +20 -0
- package/mcp/mcp_config.example.json +35 -0
- package/package.json +3 -1
- package/plugins/core/rules/core-practices.md +63 -4
- package/plugins/python-ai/rules/ai-agent-patterns.md +67 -4
- package/plugins/security-shield/rules/zero-trust.md +60 -4
- package/plugins/web-fullstack/rules/frontend-standards.md +74 -4
- package/rules/paradigms/security-hardened.md +53 -10
- package/rules/paradigms/tdd.md +65 -8
- package/scripts/install.ps1 +14 -0
- package/scripts/install.sh +15 -1
- package/scripts/validate.sh +103 -12
- package/skills/agent-evals/SKILL.md +61 -0
- package/skills/apache-kafka-streams/SKILL.md +152 -0
- package/skills/argo-workflows/SKILL.md +151 -0
- package/skills/axum-web-service/SKILL.md +159 -0
- package/skills/cilium-ebpf-networking/SKILL.md +145 -0
- package/skills/clickhouse-analytics/SKILL.md +128 -0
- package/skills/dbt-transformation/SKILL.md +179 -0
- package/skills/debezium-cdc/SKILL.md +166 -0
- package/skills/docker-compose-orchestrator/SKILL.md +85 -0
- package/skills/duckdb-local-olap/SKILL.md +134 -0
- package/skills/fastapi-production/SKILL.md +157 -0
- package/skills/graphql-architect/SKILL.md +78 -0
- package/skills/grpc-connect-rpc/SKILL.md +176 -0
- package/skills/langgraph-orchestrator/SKILL.md +144 -0
- package/skills/litellm-proxy-gateway/SKILL.md +154 -0
- package/skills/nats-jetstream/SKILL.md +122 -0
- package/skills/open-telemetry-tracing/SKILL.md +151 -0
- package/skills/playwright-visual-regression/SKILL.md +124 -0
- package/skills/redis-cache-patterns/SKILL.md +159 -0
- package/skills/svelte-kit-architect/SKILL.md +190 -0
- package/skills/temporal-workflows/SKILL.md +158 -0
- package/skills/trpc-react-query/SKILL.md +169 -0
- package/skills/turborepo-monorepo/SKILL.md +199 -0
- package/skills/vllm-inference/SKILL.md +144 -0
- package/skills/wasm-rust-optimizer/SKILL.md +130 -0
- package/templates/full-power/hooks.json +14 -0
- package/templates/full-power/mcp_config.json +43 -0
- package/templates/recommended/hooks.json +14 -0
- package/tests/cli.test.js +383 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fastapi-production
|
|
3
|
+
description: >-
|
|
4
|
+
Architects, builds, and reviews production-grade async FastAPI backends with Pydantic v2, lifespan context management, JWT auth, dependency injection, and health probes.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# FastAPI Production Architect
|
|
8
|
+
|
|
9
|
+
This skill guides building high-performance, asynchronous REST APIs with FastAPI, adhering to production standards, strict type safety with Pydantic v2, clean dependency injection, and cloud-native observability.
|
|
10
|
+
|
|
11
|
+
## 🏗️ Production Directory Layout
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
app/
|
|
15
|
+
├── api/
|
|
16
|
+
│ ├── deps.py # Shared dependencies (DB sessions, current user, rate limiters)
|
|
17
|
+
│ └── v1/
|
|
18
|
+
│ ├── router.py # Root v1 router aggregating feature endpoints
|
|
19
|
+
│ └── endpoints/
|
|
20
|
+
│ ├── auth.py # Authentication & token renewal
|
|
21
|
+
│ └── users.py # User management endpoints
|
|
22
|
+
├── core/
|
|
23
|
+
│ ├── config.py # Pydantic BaseSettings environment validation
|
|
24
|
+
│ ├── database.py # Async SQLAlchemy engine & session factory
|
|
25
|
+
│ └── security.py # JWT encoding/decoding & Argon2/bcrypt hashing
|
|
26
|
+
├── models/ # SQLAlchemy ORM database models
|
|
27
|
+
├── schemas/ # Pydantic v2 request/response schemas
|
|
28
|
+
├── services/ # Pure domain business logic
|
|
29
|
+
└── main.py # FastAPI application initialization & lifespan
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## ⚡ Core Patterns
|
|
35
|
+
|
|
36
|
+
### 1. Lifespan State Management
|
|
37
|
+
|
|
38
|
+
Avoid deprecated `@app.on_event("startup")` and `@app.on_event("shutdown")`. Use modern async context lifespans:
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from contextlib import asynccontextmanager
|
|
42
|
+
from fastapi import FastAPI
|
|
43
|
+
from app.core.database import engine
|
|
44
|
+
from app.core.redis import init_redis_pool, close_redis_pool
|
|
45
|
+
|
|
46
|
+
@asynccontextmanager
|
|
47
|
+
async def lifespan(app: FastAPI):
|
|
48
|
+
# Startup: Initialize connection pools, caches, and telemetry
|
|
49
|
+
app.state.redis = await init_redis_pool()
|
|
50
|
+
try:
|
|
51
|
+
yield
|
|
52
|
+
finally:
|
|
53
|
+
# Shutdown: Gracefully drain connections
|
|
54
|
+
await close_redis_pool(app.state.redis)
|
|
55
|
+
await engine.dispose()
|
|
56
|
+
|
|
57
|
+
app = FastAPI(title="Production Service", lifespan=lifespan)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 2. Pydantic v2 Request & Response Schemas
|
|
61
|
+
|
|
62
|
+
Enforce strict validation, immutable attributes where appropriate, and forbid undeclared payloads:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
|
66
|
+
|
|
67
|
+
class UserBase(BaseModel):
|
|
68
|
+
model_config = ConfigDict(
|
|
69
|
+
from_attributes=True,
|
|
70
|
+
extra="forbid",
|
|
71
|
+
str_strip_whitespace=True,
|
|
72
|
+
)
|
|
73
|
+
email: EmailStr
|
|
74
|
+
is_active: bool = True
|
|
75
|
+
|
|
76
|
+
class UserCreate(UserBase):
|
|
77
|
+
password: str = Field(min_length=8, max_length=128)
|
|
78
|
+
|
|
79
|
+
class UserResponse(UserBase):
|
|
80
|
+
id: int
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 3. Dependency Injection & Database Sessions
|
|
84
|
+
|
|
85
|
+
Inject asynchronous SQLAlchemy sessions using an `async_sessionmaker` generator yielding into FastAPI's `Depends`:
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
from collections.abc import AsyncGenerator
|
|
89
|
+
from fastapi import Depends
|
|
90
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
91
|
+
from app.core.database import async_session_factory
|
|
92
|
+
|
|
93
|
+
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
|
|
94
|
+
async with async_session_factory() as session:
|
|
95
|
+
try:
|
|
96
|
+
yield session
|
|
97
|
+
await session.commit()
|
|
98
|
+
except Exception:
|
|
99
|
+
await session.rollback()
|
|
100
|
+
raise
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### 4. JWT Authentication & Permission Guards
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from typing import Annotated
|
|
107
|
+
from fastapi import Depends, HTTPException, status
|
|
108
|
+
from fastapi.security import OAuth2PasswordBearer
|
|
109
|
+
from app.schemas.user import UserResponse
|
|
110
|
+
from app.services.auth import decode_jwt_token
|
|
111
|
+
|
|
112
|
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
|
|
113
|
+
|
|
114
|
+
async def get_current_user(token: Annotated[str, Depends(oauth2_scheme)]) -> UserResponse:
|
|
115
|
+
user = await decode_jwt_token(token)
|
|
116
|
+
if not user or not user.is_active:
|
|
117
|
+
raise HTTPException(
|
|
118
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
119
|
+
detail="Invalid authentication credentials",
|
|
120
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
121
|
+
)
|
|
122
|
+
return user
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 5. Standardized Problem Details Error Envelope (RFC 7807)
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from fastapi import Request
|
|
129
|
+
from fastapi.responses import JSONResponse
|
|
130
|
+
|
|
131
|
+
async def global_exception_handler(request: Request, exc: Exception) -> JSONResponse:
|
|
132
|
+
return JSONResponse(
|
|
133
|
+
status_code=500,
|
|
134
|
+
content={
|
|
135
|
+
"type": "https://errors.example.com/internal-server-error",
|
|
136
|
+
"title": "Internal Server Error",
|
|
137
|
+
"status": 500,
|
|
138
|
+
"detail": "An unexpected error occurred. Please contact engineering support.",
|
|
139
|
+
"instance": str(request.url.path),
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 6. Kubernetes Liveness & Readiness Probes
|
|
145
|
+
|
|
146
|
+
Expose separate endpoints for orchestrator checks:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
@app.get("/healthz/liveness", tags=["Health"])
|
|
150
|
+
async def liveness_check():
|
|
151
|
+
return {"status": "ok"}
|
|
152
|
+
|
|
153
|
+
@app.get("/healthz/readiness", tags=["Health"])
|
|
154
|
+
async def readiness_check(db: AsyncSession = Depends(get_db_session)):
|
|
155
|
+
await db.execute(text("SELECT 1"))
|
|
156
|
+
return {"status": "ready"}
|
|
157
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graphql-architect
|
|
3
|
+
description: Designs, specifies, and implements production GraphQL APIs, DataLoader N+1 query batching, Relay-style cursor pagination, and schema federation.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# GraphQL Architecture & API Craftsmanship
|
|
7
|
+
|
|
8
|
+
This skill guides the design, schema modeling, query optimization, and implementation of production-grade GraphQL APIs.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Core Principles
|
|
13
|
+
|
|
14
|
+
1. **Schema-First Design**:
|
|
15
|
+
- Model client domain requirements into a declarative Schema Definition Language (SDL) before implementing resolvers.
|
|
16
|
+
2. **Defeat the N+1 Problem**:
|
|
17
|
+
- Never query database tables inside nested resolvers without a batching mechanism (e.g., `DataLoader`).
|
|
18
|
+
3. **Cursor-Based Pagination**:
|
|
19
|
+
- For real-time or dynamic lists, implement Relay-compliant cursor pagination (`Connection`, `Edge`, `PageInfo`) rather than offset/limit pagination.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. Relay-Compliant Cursor Pagination Pattern
|
|
24
|
+
|
|
25
|
+
```graphql
|
|
26
|
+
type PageInfo {
|
|
27
|
+
hasNextPage: Boolean!
|
|
28
|
+
hasPreviousPage: Boolean!
|
|
29
|
+
startCursor: String
|
|
30
|
+
endCursor: String
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type UserEdge {
|
|
34
|
+
cursor: String!
|
|
35
|
+
node: User!
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type UserConnection {
|
|
39
|
+
edges: [UserEdge!]!
|
|
40
|
+
pageInfo: PageInfo!
|
|
41
|
+
totalCount: Int!
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type Query {
|
|
45
|
+
users(first: Int, after: String): UserConnection!
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. DataLoader Batching Blueprint
|
|
52
|
+
|
|
53
|
+
Prevent database query fan-out by batching IDs into a single SQL `IN` query per event loop tick:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import DataLoader from 'dataloader';
|
|
57
|
+
|
|
58
|
+
// Batch function loading users by array of IDs
|
|
59
|
+
const batchUsers = async (userIds: readonly string[]): Promise<(User | Error)[]> => {
|
|
60
|
+
const users = await db.user.findMany({
|
|
61
|
+
where: { id: { in: [...userIds] } },
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Map results back to exact input order
|
|
65
|
+
const userMap = new Map(users.map(u => [u.id, u]));
|
|
66
|
+
return userIds.map(id => userMap.get(id) || new Error(`User ${id} not found`));
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const createUserDataLoader = () => new DataLoader(batchUsers);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 4. Query Complexity & Depth Limiting
|
|
75
|
+
|
|
76
|
+
To prevent Denial-of-Service attacks through cyclic or deeply nested queries:
|
|
77
|
+
- Enforce maximum query depth (e.g., max 6 levels).
|
|
78
|
+
- Assign cost multipliers to nested connections to reject queries exceeding complexity thresholds.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grpc-connect-rpc
|
|
3
|
+
description: >-
|
|
4
|
+
Architects and implements high-performance, browser-compatible gRPC and Protocol Buffer services using Connect-RPC (Connect-ES & Connect-Go), HTTP/2 & HTTP/3 streaming, and type-safe schema generation.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Connect-RPC & Modern Protocol Buffers
|
|
8
|
+
|
|
9
|
+
This skill guides building fast, ergonomic, and 100% browser-compatible RPC services using Connect-RPC (by Buf). Connect implements the gRPC, gRPC-Web, and Connect protocols natively over HTTP/1.1, HTTP/2, and HTTP/3 without requiring Envoy proxy sidecars.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Core Patterns
|
|
14
|
+
|
|
15
|
+
### 1. Protobuf Service Definition (`buf.build` Standard)
|
|
16
|
+
|
|
17
|
+
Define service contracts and strongly-typed data structures:
|
|
18
|
+
|
|
19
|
+
```protobuf
|
|
20
|
+
// proto/commerce/v1/order.proto
|
|
21
|
+
syntax = "proto3";
|
|
22
|
+
|
|
23
|
+
package commerce.v1;
|
|
24
|
+
|
|
25
|
+
option go_package = "github.com/company/commerce/gen/commerce/v1;commercev1";
|
|
26
|
+
|
|
27
|
+
service OrderService {
|
|
28
|
+
rpc CreateOrder(CreateOrderRequest) returns (CreateOrderResponse);
|
|
29
|
+
rpc StreamOrderUpdates(StreamOrderUpdatesRequest) returns (stream StreamOrderUpdatesResponse);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
message CreateOrderRequest {
|
|
33
|
+
string customer_id = 1;
|
|
34
|
+
repeated OrderItem items = 2;
|
|
35
|
+
double total_usd = 3;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
message OrderItem {
|
|
39
|
+
string sku = 1;
|
|
40
|
+
int32 quantity = 2;
|
|
41
|
+
double price_usd = 3;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
message CreateOrderResponse {
|
|
45
|
+
string order_id = 1;
|
|
46
|
+
string status = 2;
|
|
47
|
+
int64 created_at_unix = 3;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
message StreamOrderUpdatesRequest {
|
|
51
|
+
string order_id = 1;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
message StreamOrderUpdatesResponse {
|
|
55
|
+
string order_id = 1;
|
|
56
|
+
string current_status = 2;
|
|
57
|
+
string message = 3;
|
|
58
|
+
int64 timestamp = 4;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Compile with `buf generate`:
|
|
63
|
+
|
|
64
|
+
```yaml
|
|
65
|
+
# buf.gen.yaml
|
|
66
|
+
version: v2
|
|
67
|
+
plugins:
|
|
68
|
+
- local: protoc-gen-es
|
|
69
|
+
out: gen/ts
|
|
70
|
+
opt: target=ts
|
|
71
|
+
- local: protoc-gen-connect-es
|
|
72
|
+
out: gen/ts
|
|
73
|
+
opt: target=ts
|
|
74
|
+
- local: protoc-gen-go
|
|
75
|
+
out: gen/go
|
|
76
|
+
opt: paths=source_relative
|
|
77
|
+
- local: protoc-gen-connect-go
|
|
78
|
+
out: gen/go
|
|
79
|
+
opt: paths=source_relative
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
### 2. Node.js / TypeScript Server Implementation (Connect-ES)
|
|
85
|
+
|
|
86
|
+
Implement the typed service handler with zero boilerplate:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { ConnectRouter } from '@connectrpc/connect';
|
|
90
|
+
import { OrderService } from './gen/ts/commerce/v1/order_connect';
|
|
91
|
+
import { fastify } from 'fastify';
|
|
92
|
+
import { fastifyConnectPlugin } from '@connectrpc/connect-fastify';
|
|
93
|
+
|
|
94
|
+
function routes(router: ConnectRouter) {
|
|
95
|
+
router.service(OrderService, {
|
|
96
|
+
async createOrder(req) {
|
|
97
|
+
if (!req.customerId || req.items.length === 0) {
|
|
98
|
+
throw new ConnectError('Order must contain a customerId and items', Code.InvalidArgument);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const orderId = `ord_${crypto.randomUUID().slice(0, 8)}`;
|
|
102
|
+
return {
|
|
103
|
+
orderId,
|
|
104
|
+
status: 'PENDING_PAYMENT',
|
|
105
|
+
createdAtUnix: BigInt(Date.now()),
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
async *streamOrderUpdates(req) {
|
|
110
|
+
const statuses = ['PAYMENT_CONFIRMED', 'WAREHOUSE_PICKED', 'IN_TRANSIT', 'DELIVERED'];
|
|
111
|
+
for (const status of statuses) {
|
|
112
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
113
|
+
yield {
|
|
114
|
+
orderId: req.orderId,
|
|
115
|
+
currentStatus: status,
|
|
116
|
+
message: `Package status updated to ${status}`,
|
|
117
|
+
timestamp: BigInt(Date.now()),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const server = fastify({ http2: true });
|
|
125
|
+
await server.register(fastifyConnectPlugin, { routes });
|
|
126
|
+
await server.listen({ host: '0.0.0.0', port: 8080 });
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
### 3. Native Browser Client (No Envoy Proxy Needed)
|
|
132
|
+
|
|
133
|
+
Invoke typed RPCs directly from modern browsers or Next.js applications:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { createClient } from '@connectrpc/connect';
|
|
137
|
+
import { createConnectTransport } from '@connectrpc/connect-web';
|
|
138
|
+
import { OrderService } from './gen/ts/commerce/v1/order_connect';
|
|
139
|
+
|
|
140
|
+
// Transport supports pure HTTP POST requests with JSON or binary Protobuf envelopes
|
|
141
|
+
const transport = createConnectTransport({
|
|
142
|
+
baseUrl: 'https://api.example.com',
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const client = createClient(OrderService, transport);
|
|
146
|
+
|
|
147
|
+
// 1. Unary RPC Call
|
|
148
|
+
const response = await client.createOrder({
|
|
149
|
+
customerId: 'cust_98234',
|
|
150
|
+
items: [{ sku: 'CLOUD-GPU-A100', quantity: 2, priceUsd: 1450.0 }],
|
|
151
|
+
totalUsd: 2900.0,
|
|
152
|
+
});
|
|
153
|
+
console.log('Created order:', response.orderId);
|
|
154
|
+
|
|
155
|
+
// 2. Server Streaming RPC Call
|
|
156
|
+
for await (const update of client.streamOrderUpdates({ orderId: response.orderId })) {
|
|
157
|
+
console.log(`Live Status [${update.currentStatus}]: ${update.message}`);
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🎯 Verification & Diagnostics
|
|
164
|
+
|
|
165
|
+
1. **Test Service with cURL (Standard HTTP POST)**:
|
|
166
|
+
```bash
|
|
167
|
+
curl \
|
|
168
|
+
--header "Content-Type: application/json" \
|
|
169
|
+
--data '{"customerId": "cust_123", "items": [{"sku": "PROD-1", "quantity": 1, "priceUsd": 99.0}], "totalUsd": 99.0}' \
|
|
170
|
+
https://api.example.com/commerce.v1.OrderService/CreateOrder
|
|
171
|
+
```
|
|
172
|
+
2. **Inspect Buf Lint & Breaking Change Rules**:
|
|
173
|
+
```bash
|
|
174
|
+
buf lint
|
|
175
|
+
buf breaking --against ".git#branch=main"
|
|
176
|
+
```
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: langgraph-orchestrator
|
|
3
|
+
description: >-
|
|
4
|
+
Designs and implements stateful multi-agent systems, cyclic graphs, persistent checkpoints, human-in-the-loop pauses, and streaming orchestration using LangGraph (Python/TypeScript).
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# LangGraph Multi-Agent Orchestration & Stateful Graphs
|
|
8
|
+
|
|
9
|
+
This skill guides the design, construction, and deployment of complex multi-agent architectures using LangGraph. It provides deterministic patterns for cyclic routing, persistent graph checkpointing, and human-in-the-loop (HITL) approval gates.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Core Concepts
|
|
14
|
+
|
|
15
|
+
1. **State Graph (`StateGraph`)**: Typed dictionary or Pydantic state passed through graph nodes.
|
|
16
|
+
2. **Nodes**: Discrete execution functions that receive current state and return state updates.
|
|
17
|
+
3. **Edges & Conditional Edges**: Transition rules between nodes (deterministic or LLM-routed).
|
|
18
|
+
4. **Checkpointers (`BaseCheckpointSaver`)**: Persists graph state across turns and enables time-travel debugging.
|
|
19
|
+
5. **Human-in-the-Loop (`interrupt_before`)**: Pauses execution graph at critical checkpoints for human intervention.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🏗️ Production Implementation (Python)
|
|
24
|
+
|
|
25
|
+
### 1. State Definition & Reducers (`state.py`)
|
|
26
|
+
|
|
27
|
+
Define immutable state schemas with explicit reducer operators:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from typing import Annotated, Sequence, TypedDict
|
|
31
|
+
from langchain_core.messages import BaseMessage
|
|
32
|
+
from langgraph.graph.message import add_messages
|
|
33
|
+
|
|
34
|
+
class AgentState(TypedDict):
|
|
35
|
+
# add_messages reducer appends new messages rather than overwriting
|
|
36
|
+
messages: Annotated[Sequence[BaseMessage], add_messages]
|
|
37
|
+
sender: str
|
|
38
|
+
iteration_count: int
|
|
39
|
+
is_approved: bool
|
|
40
|
+
context_data: dict
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### 2. Multi-Agent Nodes & Graph Assembly (`graph.py`)
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from langgraph.graph import StateGraph, END, START
|
|
49
|
+
from langgraph.checkpoint.memory import MemorySaver
|
|
50
|
+
from langchain_core.messages import AIMessage, HumanMessage
|
|
51
|
+
|
|
52
|
+
def researcher_node(state: AgentState) -> dict:
|
|
53
|
+
"""Researches user inquiry and extracts factual grounding."""
|
|
54
|
+
# LLM invocation logic here
|
|
55
|
+
result = "Research findings: latency reduced by 40% via caching."
|
|
56
|
+
return {
|
|
57
|
+
"messages": [AIMessage(content=result, name="researcher")],
|
|
58
|
+
"sender": "researcher",
|
|
59
|
+
"iteration_count": state.get("iteration_count", 0) + 1,
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
def reviewer_node(state: AgentState) -> dict:
|
|
63
|
+
"""Validates research quality and enforces compliance."""
|
|
64
|
+
last_msg = state["messages"][-1].content
|
|
65
|
+
approved = "latency" in last_msg.lower()
|
|
66
|
+
return {
|
|
67
|
+
"messages": [AIMessage(content="Review complete.", name="reviewer")],
|
|
68
|
+
"sender": "reviewer",
|
|
69
|
+
"is_approved": approved,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
def human_approval_node(state: AgentState) -> dict:
|
|
73
|
+
"""Node executed after human approval gate."""
|
|
74
|
+
return {"messages": [AIMessage(content="Action executed after sign-off.", name="human_gate")]}
|
|
75
|
+
|
|
76
|
+
def router_condition(state: AgentState) -> str:
|
|
77
|
+
"""Evaluate whether to loop or terminate."""
|
|
78
|
+
if state.get("is_approved", False):
|
|
79
|
+
return "human_approval"
|
|
80
|
+
if state.get("iteration_count", 0) >= 3:
|
|
81
|
+
return "abort"
|
|
82
|
+
return "researcher"
|
|
83
|
+
|
|
84
|
+
# Build State Graph
|
|
85
|
+
workflow = StateGraph(AgentState)
|
|
86
|
+
|
|
87
|
+
# Add Nodes
|
|
88
|
+
workflow.add_node("researcher", researcher_node)
|
|
89
|
+
workflow.add_node("reviewer", reviewer_node)
|
|
90
|
+
workflow.add_node("human_approval", human_approval_node)
|
|
91
|
+
|
|
92
|
+
# Add Edges
|
|
93
|
+
workflow.add_edge(START, "researcher")
|
|
94
|
+
workflow.add_edge("researcher", "reviewer")
|
|
95
|
+
workflow.add_conditional_edges(
|
|
96
|
+
"reviewer",
|
|
97
|
+
router_condition,
|
|
98
|
+
{
|
|
99
|
+
"human_approval": "human_approval",
|
|
100
|
+
"researcher": "researcher",
|
|
101
|
+
"abort": END,
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
workflow.add_edge("human_approval", END)
|
|
105
|
+
|
|
106
|
+
# Compile with Persistent Checkpointer and Human-in-the-Loop Interruption
|
|
107
|
+
checkpointer = MemorySaver()
|
|
108
|
+
app = workflow.compile(
|
|
109
|
+
checkpointer=checkpointer,
|
|
110
|
+
interrupt_before=["human_approval"]
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### 3. Execution & Human-in-the-Loop Resumption
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
thread_config = {"configurable": {"thread_id": "session-prod-1024"}}
|
|
120
|
+
|
|
121
|
+
# Run until human interrupt
|
|
122
|
+
inputs = {"messages": [HumanMessage(content="Optimize database latency.")], "iteration_count": 0}
|
|
123
|
+
for event in app.stream(inputs, config=thread_config):
|
|
124
|
+
print(f"Step: {event}")
|
|
125
|
+
|
|
126
|
+
# Inspect current snapshot before approval
|
|
127
|
+
snapshot = app.get_state(thread_config)
|
|
128
|
+
print(f"Next Node Pending Approval: {snapshot.next}")
|
|
129
|
+
|
|
130
|
+
# Resume graph after human confirmation
|
|
131
|
+
for event in app.stream(None, config=thread_config):
|
|
132
|
+
print(f"Post-approval Step: {event}")
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 🛡️ Best Practices & Anti-Patterns
|
|
138
|
+
|
|
139
|
+
| Category | ❌ Anti-Pattern | ✅ Production Best Practice |
|
|
140
|
+
| :--- | :--- | :--- |
|
|
141
|
+
| **State Mutation** | Modifying state objects in-place | Return clean partial state dictionaries with reducer keys |
|
|
142
|
+
| **Cycles** | Unbounded recursive loops | Enforce explicit `iteration_count` or recursion limit (`recursion_limit=25`) |
|
|
143
|
+
| **Checkpoints** | Storing giant binary blobs in state | Keep state lean; persist media in object stores (GCS/S3) and store URIs |
|
|
144
|
+
| **HITL** | Hardcoded polling loops | Use native `interrupt_before` / `interrupt_after` with thread configurations |
|