everything-gemini 2.0.0 → 2.2.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/BENCHMARK.md +106 -0
- package/CHANGELOG.md +42 -0
- package/PARTNERSHIP.md +100 -0
- package/README.md +27 -4
- package/ROADMAP_AGI_v3.0.md +109 -0
- package/bin/everything-gemini +568 -11
- package/docs/LAUNCH_KIT_v2.1.0.md +118 -0
- package/docs/LAUNCH_KIT_v2.2.0.md +168 -0
- package/docs/index.html +20 -8
- package/examples/python-sdk/README.md +4 -0
- package/examples/python-sdk/harness2_recursive_loop.py +240 -0
- package/hooks/budget-guard/hooks.json +16 -0
- package/hooks/budget-guard/scripts/budget-gate.sh +57 -0
- package/hooks/human-gate/hooks.json +16 -0
- package/hooks/human-gate/scripts/human-gate.sh +67 -0
- package/package.json +1 -1
- package/scripts/harness_rollback.sh +26 -0
- package/scripts/harness_snapshot.sh +30 -0
- package/scripts/validate.sh +1 -1
- package/skills/bigquery-vector-search/SKILL.md +205 -0
- package/skills/cloud-run-agents/SKILL.md +167 -0
- package/skills/context-warmer/SKILL.md +140 -0
- package/skills/dataproc-spark-analytics/SKILL.md +120 -0
- package/skills/google-flow-orchestrator/SKILL.md +174 -0
- package/skills/harness2-recursive-optimization/SKILL.md +240 -0
- package/skills/pubsub-event-mesh/SKILL.md +179 -0
- package/skills/spanner-graph-rag/SKILL.md +167 -0
- package/tests/cli.test.js +134 -9
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pubsub-event-mesh
|
|
3
|
+
description: Implements Google Cloud Pub/Sub asynchronous event mesh architectures, exactly-once delivery, dead-letter queues, and schema-validated multi-agent message routing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Google Cloud Pub/Sub Multi-Agent Event Mesh
|
|
7
|
+
|
|
8
|
+
Architects and deploys scalable, decoupled asynchronous messaging pipelines for autonomous multi-agent coordination using Google Cloud Pub/Sub. Covers dead-letter queues (DLQ), exactly-once delivery, schema validation (Protobuf / Avro), and resilient streaming subscribers.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Architecture: Multi-Agent Asynchronous Event Mesh
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Google Cloud Pub/Sub Event Mesh
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ AGENT WORKFLOW BUS │
|
|
18
|
+
│ │
|
|
19
|
+
│ ┌─────────────────────┐ ┌───────────────────────────┐ │
|
|
20
|
+
│ │ Subagent Initiator │ │ Schema Validator │ │
|
|
21
|
+
│ │ (e.g. Planner) │ │ (Protobuf / Avro Message) │ │
|
|
22
|
+
│ └──────────┬──────────┘ └─────────────┬─────────────┘ │
|
|
23
|
+
│ │ │ │
|
|
24
|
+
│ ▼ ▼ │
|
|
25
|
+
│ [topic: agent-tasks] ───────────────────────► [topic: agent-tasks] │
|
|
26
|
+
│ │ │
|
|
27
|
+
│ ├─────────────────────────────┬────────────────────────────┐ │
|
|
28
|
+
│ ▼ ▼ ▼ │
|
|
29
|
+
│ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────┴─┐ │
|
|
30
|
+
│ │ Subscription: │ │ Subscription: │ │ DLQ Topic: │ │
|
|
31
|
+
│ │ Code Reviewer Agent │ │ Security Audit Agent │ │ agent-dlq │ │
|
|
32
|
+
│ │ (Exactly-Once Ack) │ │ (Streaming Pull) │ │ (Max Retries)│
|
|
33
|
+
│ └──────────────────────┘ └──────────────────────┘ └────────────┘ │
|
|
34
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Infrastructure Setup (`gcloud`)
|
|
40
|
+
|
|
41
|
+
Provision an enterprise topic with Dead-Letter Queue (DLQ) isolation and exactly-once delivery:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 1. Create Dead-Letter Queue (DLQ) topic and subscription for failed task events
|
|
45
|
+
gcloud pubsub topics create agent-task-dlq
|
|
46
|
+
gcloud pubsub subscriptions create agent-task-dlq-sub --topic=agent-task-dlq
|
|
47
|
+
|
|
48
|
+
# 2. Create primary agent task topic
|
|
49
|
+
gcloud pubsub topics create agent-task-bus \
|
|
50
|
+
--message-retention-duration=7d
|
|
51
|
+
|
|
52
|
+
# 3. Create consumer subscription with exactly-once delivery and DLQ routing
|
|
53
|
+
gcloud pubsub subscriptions create code-reviewer-sub \
|
|
54
|
+
--topic=agent-task-bus \
|
|
55
|
+
--ack-deadline=120 \
|
|
56
|
+
--enable-exactly-once-delivery \
|
|
57
|
+
--dead-letter-topic=agent-task-dlq \
|
|
58
|
+
--max-delivery-attempts=5 \
|
|
59
|
+
--min-retry-delay=10s \
|
|
60
|
+
--max-retry-delay=600s
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 3. Python Event Mesh Publisher
|
|
66
|
+
|
|
67
|
+
Publishes structured multi-agent execution events with idempotency ordering keys and tracing attributes:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
import json
|
|
71
|
+
import uuid
|
|
72
|
+
from google.cloud import pubsub_v1
|
|
73
|
+
|
|
74
|
+
publisher = pubsub_v1.PublisherClient()
|
|
75
|
+
topic_path = publisher.topic_path("my_project", "agent-task-bus")
|
|
76
|
+
|
|
77
|
+
def publish_agent_task(
|
|
78
|
+
task_id: str,
|
|
79
|
+
target_agent: str,
|
|
80
|
+
payload: dict,
|
|
81
|
+
correlation_id: str = None
|
|
82
|
+
) -> str:
|
|
83
|
+
"""Publishes an agent task with ordering key and strict metadata tags."""
|
|
84
|
+
correlation_id = correlation_id or str(uuid.uuid4())
|
|
85
|
+
|
|
86
|
+
message_data = json.dumps({
|
|
87
|
+
"taskId": task_id,
|
|
88
|
+
"targetAgent": target_agent,
|
|
89
|
+
"payload": payload,
|
|
90
|
+
"timestamp": "2026-10-21T11:00:00Z"
|
|
91
|
+
}).encode("utf-8")
|
|
92
|
+
|
|
93
|
+
# Publish with attributes for server-side subscription filtering
|
|
94
|
+
future = publisher.publish(
|
|
95
|
+
topic_path,
|
|
96
|
+
data=message_data,
|
|
97
|
+
target_agent=target_agent,
|
|
98
|
+
correlation_id=correlation_id,
|
|
99
|
+
ordering_key=task_id # Ensures sequential processing for the same task
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
message_id = future.result()
|
|
103
|
+
print(f"🚀 Published task {task_id} to Pub/Sub (Msg ID: {message_id})")
|
|
104
|
+
return message_id
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 4. Streaming Pull Subscriber with Backpressure
|
|
110
|
+
|
|
111
|
+
Consumes tasks asynchronously, processes execution via subagents, and deterministically acknowledges messages:
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from google.cloud import pubsub_v1
|
|
115
|
+
import time
|
|
116
|
+
|
|
117
|
+
subscriber = pubsub_v1.SubscriberClient()
|
|
118
|
+
sub_path = subscriber.subscription_path("my_project", "code-reviewer-sub")
|
|
119
|
+
|
|
120
|
+
def callback(message: pubsub_v1.subscriber.message.Message):
|
|
121
|
+
print(f"📥 Received task event: {message.message_id}")
|
|
122
|
+
task_payload = json.loads(message.data.decode("utf-8"))
|
|
123
|
+
|
|
124
|
+
try:
|
|
125
|
+
# Execute agent task logic
|
|
126
|
+
print(f"🤖 Processing task for {task_payload.get('targetAgent')}...")
|
|
127
|
+
# (Invoke subagent logic here)
|
|
128
|
+
|
|
129
|
+
# Acknowledge receipt upon successful execution
|
|
130
|
+
message.ack()
|
|
131
|
+
print(f"✅ Successfully acknowledged message {message.message_id}")
|
|
132
|
+
except Exception as exc:
|
|
133
|
+
print(f"❌ Task processing failed: {exc}")
|
|
134
|
+
# Negative acknowledgment triggers retry / DLQ forwarding
|
|
135
|
+
message.nack()
|
|
136
|
+
|
|
137
|
+
# Configure flow control to prevent memory exhaustion during spikes
|
|
138
|
+
flow_control = pubsub_v1.types.FlowControl(
|
|
139
|
+
max_messages=10,
|
|
140
|
+
max_bytes=50 * 1024 * 1024 # 50MB
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
streaming_pull = subscriber.subscribe(
|
|
144
|
+
sub_path,
|
|
145
|
+
callback=callback,
|
|
146
|
+
flow_control=flow_control
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
print(f"🎧 Listening for agent tasks on {sub_path}...")
|
|
150
|
+
try:
|
|
151
|
+
streaming_pull.result()
|
|
152
|
+
except KeyboardInterrupt:
|
|
153
|
+
streaming_pull.cancel()
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 5. Subscription-Level Filtering
|
|
159
|
+
|
|
160
|
+
Avoid spinning up unnecessary subagents by filtering messages at the Pub/Sub server level:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Create subscription that ONLY receives tasks addressed to 'security-auditor'
|
|
164
|
+
gcloud pubsub subscriptions create security-auditor-sub \
|
|
165
|
+
--topic=agent-task-bus \
|
|
166
|
+
--message-filter='attributes.target_agent = "security-auditor"' \
|
|
167
|
+
--enable-exactly-once-delivery
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## 6. Resilience & Anti-Patterns Checklist
|
|
173
|
+
|
|
174
|
+
| Category | Recommended Pattern | Anti-Pattern |
|
|
175
|
+
| :--- | :--- | :--- |
|
|
176
|
+
| **Delivery Guarantee** | Enable `--enable-exactly-once-delivery` for state mutation events | Using default at-least-once for irreversible codebase commits |
|
|
177
|
+
| **Dead Lettering** | Always bind `--dead-letter-topic` with `--max-delivery-attempts=5` | Infinite retry loops crashing worker containers on poisoned tasks |
|
|
178
|
+
| **Flow Control** | Restrict concurrent in-flight messages with `FlowControl(max_messages=10)` | Unbounded pulling leading to OOM kills during burst invocations |
|
|
179
|
+
| **Ordering** | Use `ordering_key` when tasks depend on prerequisite steps | Random partition dispatch causing out-of-order build/deploy tasks |
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spanner-graph-rag
|
|
3
|
+
description: Implements Google Cloud Spanner Graph schemas, ISO GQL queries, knowledge graph traversal, and hybrid graph-vector RAG pipelines for Gemini agents.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Spanner Graph & Knowledge Graph RAG
|
|
7
|
+
|
|
8
|
+
Designs, provisions, and queries distributed enterprise knowledge graphs using Google Cloud Spanner Graph. Implements ISO GQL (Graph Query Language) multi-hop traversals, cyclic graph pattern matching, and hybrid Graph-Vector RAG to eliminate hallucinations across complex organizational entity networks.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Architecture: Graph-Grounded Agentic Reasoning
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Google Cloud Spanner
|
|
16
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
17
|
+
│ SPANNER DISTRIBUTED GRAPH ENGINE │
|
|
18
|
+
│ │
|
|
19
|
+
│ ┌─────────────────────┐ ┌───────────────────────────┐ │
|
|
20
|
+
│ │ Node Table: Account │ │ Node Table: Microservice │ │
|
|
21
|
+
│ │ (Enterprise Org) │ │ (Infrastructure Artifact) │ │
|
|
22
|
+
│ └──────────┬──────────┘ └─────────────┬─────────────┘ │
|
|
23
|
+
│ │ │ │
|
|
24
|
+
│ │ Edge: OWNS Edge: CALLS │ │
|
|
25
|
+
│ └────────────────► [TEAM] ───────────────────┘ │
|
|
26
|
+
│ │ │
|
|
27
|
+
│ ▼ │
|
|
28
|
+
│ ┌─────────────────────────────┐ │
|
|
29
|
+
│ │ Edge: MUTATES_RESOURCE │ │
|
|
30
|
+
│ │ Destination: Cloud Database │ │
|
|
31
|
+
│ └──────────────┬──────────────┘ │
|
|
32
|
+
│ │ │
|
|
33
|
+
│ ▼ │
|
|
34
|
+
│ ┌───────────────────────────────────────────────┐ │
|
|
35
|
+
│ │ ISO GQL Multi-Hop Graph Traversal │ │
|
|
36
|
+
│ │ MATCH (t:Team)-[:CALLS*1..3]->(m:Service) │ │
|
|
37
|
+
│ └──────────────────────┬────────────────────────┘ │
|
|
38
|
+
│ │ Grounded Entity Context │
|
|
39
|
+
│ ▼ │
|
|
40
|
+
│ ┌───────────────────────────────────────────────┐ │
|
|
41
|
+
│ │ Gemini 2.0 / 3.8 Reasoning & Action Engine │ │
|
|
42
|
+
│ │ Zero hallucination on architectural blast radius│ │
|
|
43
|
+
│ └───────────────────────────────────────────────┘ │
|
|
44
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 2. Spanner Graph DDL (`CREATE PROPERTY GRAPH`)
|
|
50
|
+
|
|
51
|
+
Define nodes, edges, and relationship labels on top of strongly consistent Spanner tables:
|
|
52
|
+
|
|
53
|
+
```sql
|
|
54
|
+
-- 1. Base Relational Tables
|
|
55
|
+
CREATE TABLE Services (
|
|
56
|
+
service_id STRING(64) NOT NULL,
|
|
57
|
+
name STRING(128) NOT NULL,
|
|
58
|
+
tier STRING(32) NOT NULL,
|
|
59
|
+
owner_team STRING(64) NOT NULL,
|
|
60
|
+
created_at TIMESTAMP OPTIONS (allow_commit_timestamp = true)
|
|
61
|
+
) PRIMARY KEY (service_id);
|
|
62
|
+
|
|
63
|
+
CREATE TABLE Dependencies (
|
|
64
|
+
caller_id STRING(64) NOT NULL,
|
|
65
|
+
target_id STRING(64) NOT NULL,
|
|
66
|
+
protocol STRING(32) NOT NULL,
|
|
67
|
+
criticality STRING(16) NOT NULL,
|
|
68
|
+
CONSTRAINT FK_Caller FOREIGN KEY (caller_id) REFERENCES Services (service_id),
|
|
69
|
+
CONSTRAINT FK_Target FOREIGN KEY (target_id) REFERENCES Services (service_id)
|
|
70
|
+
) PRIMARY KEY (caller_id, target_id);
|
|
71
|
+
|
|
72
|
+
-- 2. Property Graph Definition (ISO GQL Standard)
|
|
73
|
+
CREATE PROPERTY GRAPH ServiceArchitectureGraph
|
|
74
|
+
VERTEX TABLES (
|
|
75
|
+
Services
|
|
76
|
+
LABEL Service
|
|
77
|
+
PROPERTIES (service_id, name, tier, owner_team)
|
|
78
|
+
)
|
|
79
|
+
EDGE TABLES (
|
|
80
|
+
Dependencies
|
|
81
|
+
SOURCE KEY (caller_id) REFERENCES Services (service_id)
|
|
82
|
+
DESTINATION KEY (target_id) REFERENCES Services (service_id)
|
|
83
|
+
LABEL CALLS
|
|
84
|
+
PROPERTIES (protocol, criticality)
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 3. ISO GQL Graph Traversal Queries
|
|
91
|
+
|
|
92
|
+
Execute declarative graph pattern matching directly in Spanner SQL:
|
|
93
|
+
|
|
94
|
+
```sql
|
|
95
|
+
-- Multi-hop blast-radius query: Find all downstream services impacted by an outage
|
|
96
|
+
GRAPH ServiceArchitectureGraph
|
|
97
|
+
MATCH (root:Service {service_id: 'payment-gateway'})
|
|
98
|
+
-[:CALLS*1..3]-> (downstream:Service)
|
|
99
|
+
WHERE downstream.tier = 'TIER_1'
|
|
100
|
+
RETURN DISTINCT
|
|
101
|
+
root.name AS failing_service,
|
|
102
|
+
downstream.name AS impacted_dependency,
|
|
103
|
+
downstream.owner_team AS oncall_team;
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 4. Python SDK Graph-Vector RAG Pipeline
|
|
109
|
+
|
|
110
|
+
Combines topological graph queries with Gemini reasoning to assess infrastructure change risk:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from google.cloud import spanner
|
|
114
|
+
from google import genai
|
|
115
|
+
|
|
116
|
+
spanner_client = spanner.Client()
|
|
117
|
+
instance = spanner_client.instance("production-instance")
|
|
118
|
+
database = instance.database("architecture-db")
|
|
119
|
+
gemini_client = genai.Client()
|
|
120
|
+
|
|
121
|
+
def analyze_architectural_blast_radius(failing_service_id: str) -> str:
|
|
122
|
+
"""Executes ISO GQL query in Spanner Graph and reasons over downstream risks with Gemini."""
|
|
123
|
+
gql_query = """
|
|
124
|
+
GRAPH ServiceArchitectureGraph
|
|
125
|
+
MATCH (s:Service {service_id: @serviceId})-[e:CALLS*1..4]->(dep:Service)
|
|
126
|
+
RETURN DISTINCT s.name AS root_service, dep.name AS dependency, dep.tier AS tier, dep.owner_team AS team
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
with database.snapshot() as snapshot:
|
|
130
|
+
results = list(snapshot.execute_sql(
|
|
131
|
+
gql_query,
|
|
132
|
+
params={"serviceId": failing_service_id},
|
|
133
|
+
param_types={"serviceId": spanner.param_types.STRING}
|
|
134
|
+
))
|
|
135
|
+
|
|
136
|
+
# Format graph path topology into structured context
|
|
137
|
+
graph_context = "\n".join([
|
|
138
|
+
f"- Dependency: {row[1]} (Tier: {row[2]}, Team: {row[3]})"
|
|
139
|
+
for row in results
|
|
140
|
+
])
|
|
141
|
+
|
|
142
|
+
# Reason with Gemini using strictly grounded graph topology
|
|
143
|
+
prompt = f"""
|
|
144
|
+
The following microservice is experiencing an outage: {failing_service_id}
|
|
145
|
+
Here is the verified dependency graph topology from Spanner Graph:
|
|
146
|
+
{graph_context}
|
|
147
|
+
|
|
148
|
+
Provide an actionable incident response triage plan, identifying on-call escalations.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
response = gemini_client.models.generate_content(
|
|
152
|
+
model="gemini-2.0-flash",
|
|
153
|
+
contents=prompt
|
|
154
|
+
)
|
|
155
|
+
return response.text
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## 5. Enterprise Best Practices & Anti-Patterns
|
|
161
|
+
|
|
162
|
+
| Category | Recommended Pattern | Anti-Pattern |
|
|
163
|
+
| :--- | :--- | :--- |
|
|
164
|
+
| **Topology Modeling** | Use Directed Property Graphs with foreign keys enforcing referential integrity | Storing graph edges in unindexed JSON arrays |
|
|
165
|
+
| **Path Search Depth** | Bound variable-length path traversals (e.g. `[:CALLS*1..4]`) | Unbounded path queries (`[:CALLS*]`) causing exponential scans |
|
|
166
|
+
| **Hybrid RAG** | Retrieve exact entity graph topology from Spanner before prompt construction | Letting LLMs guess multi-hop dependencies from vector embeddings alone |
|
|
167
|
+
| **Transactions** | Execute read-only graph traversals inside Spanner read-only snapshots | Mixing long-running graph analyses into interactive read-write transactions |
|
package/tests/cli.test.js
CHANGED
|
@@ -90,10 +90,10 @@ it('should benchmark ecosystem components and output valid JSON with --json', ()
|
|
|
90
90
|
const res = runCli('benchmark --json');
|
|
91
91
|
assert.strictEqual(res.status, 0);
|
|
92
92
|
const data = JSON.parse(res.stdout);
|
|
93
|
-
assert.strictEqual(data.totalComponents,
|
|
94
|
-
assert.strictEqual(data.progressiveSkillsCount,
|
|
93
|
+
assert.strictEqual(data.totalComponents, 90);
|
|
94
|
+
assert.strictEqual(data.progressiveSkillsCount, 68);
|
|
95
95
|
assert.strictEqual(data.scopedAgentsCount, 13);
|
|
96
|
-
assert.strictEqual(data.lifecycleHooksCount,
|
|
96
|
+
assert.strictEqual(data.lifecycleHooksCount, 9);
|
|
97
97
|
assert(data.totalRunbookTokens > 15000, 'Expected >15,000 runbook tokens');
|
|
98
98
|
assert(data.estimatedTokensSavedPerTurn > 8000, 'Expected significant token savings');
|
|
99
99
|
});
|
|
@@ -316,7 +316,7 @@ try {
|
|
|
316
316
|
const dryRes = runCli(`bundle --output "${bundleTarget}" --dry-run`);
|
|
317
317
|
assert.strictEqual(dryRes.status, 0);
|
|
318
318
|
assert.match(dryRes.stdout, /DRY RUN MODE ACTIVATED/);
|
|
319
|
-
assert.match(dryRes.stdout, /Skills to bundle:
|
|
319
|
+
assert.match(dryRes.stdout, /Skills to bundle: 68/);
|
|
320
320
|
assert.strictEqual(fs.existsSync(bundleTarget), false, 'Dry run should not create destination directory');
|
|
321
321
|
|
|
322
322
|
// JSON Dry-run mode
|
|
@@ -324,7 +324,7 @@ try {
|
|
|
324
324
|
assert.strictEqual(jsonRes.status, 0);
|
|
325
325
|
const dryData = JSON.parse(jsonRes.stdout);
|
|
326
326
|
assert.strictEqual(dryData.dryRun, true);
|
|
327
|
-
assert.strictEqual(dryData.manifest.components.totalCount,
|
|
327
|
+
assert.strictEqual(dryData.manifest.components.totalCount, 90);
|
|
328
328
|
|
|
329
329
|
// Live mode
|
|
330
330
|
const liveRes = runCli(`bundle --output "${bundleTarget}"`);
|
|
@@ -446,6 +446,63 @@ try {
|
|
|
446
446
|
assert.match(resTriton.stdout, /Triton/);
|
|
447
447
|
});
|
|
448
448
|
|
|
449
|
+
// Info for v2.1.0 Google Research Harness2 & Google Family skills
|
|
450
|
+
it('should display info for v2.1.0 Harness2, Google Flow, and Dataproc Spark skills', () => {
|
|
451
|
+
const resH2 = runCli('info harness2-recursive-optimization');
|
|
452
|
+
assert.strictEqual(resH2.status, 0);
|
|
453
|
+
assert.match(resH2.stdout, /Harness² Recursive Optimization/);
|
|
454
|
+
|
|
455
|
+
const resFlow = runCli('info google-flow-orchestrator');
|
|
456
|
+
assert.strictEqual(resFlow.status, 0);
|
|
457
|
+
assert.match(resFlow.stdout, /Google Flow Orchestrator/);
|
|
458
|
+
|
|
459
|
+
const resSpark = runCli('info dataproc-spark-analytics');
|
|
460
|
+
assert.strictEqual(resSpark.status, 0);
|
|
461
|
+
assert.match(resSpark.stdout, /Dataproc Spark Analytics/);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// Harness2 command and export format verification
|
|
465
|
+
it('should synthesize Google Research Harness2 workspace in dry-run, live, and JSON export modes', () => {
|
|
466
|
+
const h2Target = path.join(tempWorkspace, 'harness2-test-ws');
|
|
467
|
+
|
|
468
|
+
// Dry-run mode
|
|
469
|
+
const dryRes = runCli(`harness2 "${h2Target}" --dry-run`);
|
|
470
|
+
assert.strictEqual(dryRes.status, 0);
|
|
471
|
+
assert.match(dryRes.stdout, /DRY RUN MODE ACTIVATED/);
|
|
472
|
+
assert.match(dryRes.stdout, /Previewing Google Research Harness² Surfaces/);
|
|
473
|
+
assert.strictEqual(fs.existsSync(h2Target), false, 'Dry run should not create destination directory');
|
|
474
|
+
|
|
475
|
+
// JSON Dry-run mode
|
|
476
|
+
const jsonRes = runCli(`harness2 "${h2Target}" --dry-run --json`);
|
|
477
|
+
assert.strictEqual(jsonRes.status, 0);
|
|
478
|
+
const dryData = JSON.parse(jsonRes.stdout);
|
|
479
|
+
assert.strictEqual(dryData.dryRun, true);
|
|
480
|
+
assert.strictEqual(dryData.manifest.metrics.total_skills, 68);
|
|
481
|
+
assert.strictEqual(dryData.manifest.metrics.total_subagents, 13);
|
|
482
|
+
assert.strictEqual(dryData.manifest.metrics.total_hooks, 9);
|
|
483
|
+
|
|
484
|
+
// Live mode
|
|
485
|
+
const liveRes = runCli(`harness2 "${h2Target}"`);
|
|
486
|
+
assert.strictEqual(liveRes.status, 0);
|
|
487
|
+
assert.match(liveRes.stdout, /Google Research Harness² Workspace Synthesized Successfully/);
|
|
488
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'harness.yaml')), true);
|
|
489
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'harness.json')), true);
|
|
490
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'prompts', 'GEMINI.md')), true);
|
|
491
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'memory', 'memory_spec.json')), true);
|
|
492
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'guidance', 'tool_selection_rules.md')), true);
|
|
493
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'subagents', 'planner.md')), true);
|
|
494
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'skills', 'harness2-recursive-optimization', 'SKILL.md')), true);
|
|
495
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'scripts', 'harness_probe.sh')), true);
|
|
496
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'scripts', 'harness_snapshot.sh')), true);
|
|
497
|
+
assert.strictEqual(fs.existsSync(path.join(h2Target, 'scripts', 'harness_rollback.sh')), true);
|
|
498
|
+
|
|
499
|
+
// Export with --format harness2
|
|
500
|
+
const h2ExportTarget = path.join(tempWorkspace, 'harness2-export-ws');
|
|
501
|
+
const exportRes = runCli(`export --format harness2 --output "${h2ExportTarget}"`);
|
|
502
|
+
assert.strictEqual(exportRes.status, 0);
|
|
503
|
+
assert.strictEqual(fs.existsSync(path.join(h2ExportTarget, 'harness.yaml')), true);
|
|
504
|
+
});
|
|
505
|
+
|
|
449
506
|
// Graph command verification
|
|
450
507
|
it('should render interaction graph in terminal, mermaid, and JSON formats', () => {
|
|
451
508
|
const resTerm = runCli('graph');
|
|
@@ -467,14 +524,82 @@ try {
|
|
|
467
524
|
});
|
|
468
525
|
|
|
469
526
|
// Benchmark Components Verification
|
|
470
|
-
it('should report
|
|
527
|
+
it('should report 90 components, 68 skills, and 13 subagents in benchmark --json', () => {
|
|
471
528
|
const res = runCli('benchmark --json');
|
|
472
529
|
assert.strictEqual(res.status, 0);
|
|
473
530
|
const data = JSON.parse(res.stdout);
|
|
474
|
-
assert.strictEqual(data.totalComponents,
|
|
475
|
-
assert.strictEqual(data.progressiveSkillsCount,
|
|
531
|
+
assert.strictEqual(data.totalComponents, 90, 'Total components should be 90');
|
|
532
|
+
assert.strictEqual(data.progressiveSkillsCount, 68, 'Progressive skills should be 68');
|
|
476
533
|
assert.strictEqual(data.scopedAgentsCount, 13, 'Scoped agents should be 13');
|
|
477
|
-
assert.strictEqual(data.lifecycleHooksCount,
|
|
534
|
+
assert.strictEqual(data.lifecycleHooksCount, 9, 'Lifecycle hooks should be 9');
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
// Harness² Run & Ingest-Trace tests
|
|
538
|
+
it('should support harness2 run with local benchmark, hard spend limits, and dry-run/json modes', () => {
|
|
539
|
+
const testTasksDir = path.join(tempWorkspace, 'harness2-tasks');
|
|
540
|
+
// Dry-run mode
|
|
541
|
+
const dryRes = runCli(`harness2 run --dir "${testTasksDir}" --bench local --max-usd 15 --dry-run`);
|
|
542
|
+
assert.strictEqual(dryRes.status, 0);
|
|
543
|
+
assert.match(dryRes.stdout, /DRY RUN MODE ACTIVATED/);
|
|
544
|
+
assert.match(dryRes.stdout, /Spend Ceiling: \$15\.00 USD/);
|
|
545
|
+
|
|
546
|
+
// JSON export mode
|
|
547
|
+
const jsonRes = runCli(`harness2 run --dir "${testTasksDir}" --bench local --max-usd 25 --json`);
|
|
548
|
+
assert.strictEqual(jsonRes.status, 0);
|
|
549
|
+
const runData = JSON.parse(jsonRes.stdout);
|
|
550
|
+
assert.strictEqual(runData.engine, 'everything-gemini-harness2-runner');
|
|
551
|
+
assert.strictEqual(runData.benchmark, 'local');
|
|
552
|
+
assert.strictEqual(runData.spendGuardrail.maxSpendUsd, 25);
|
|
553
|
+
assert.strictEqual(runData.result.status, 'PASSED');
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('should support harness2 ingest-trace to generate automated regression probes', () => {
|
|
557
|
+
const sampleTracePath = path.join(tempWorkspace, 'production-failure.json');
|
|
558
|
+
fs.writeFileSync(sampleTracePath, JSON.stringify({
|
|
559
|
+
id: 'trace-spark-oom',
|
|
560
|
+
error: 'OutOfMemoryError: Container killed due to 16GB memory ceiling',
|
|
561
|
+
tool: 'dataproc-spark-analytics',
|
|
562
|
+
timestamp: '2026-10-19T18:00:00Z',
|
|
563
|
+
stack: 'Fatal: JVM worker heap exhausted at SparkExecutor.scala:42'
|
|
564
|
+
}, null, 2), 'utf8');
|
|
565
|
+
|
|
566
|
+
const traceOutDir = path.join(tempWorkspace, 'regression-tasks');
|
|
567
|
+
const ingestRes = runCli(`harness2 ingest-trace "${sampleTracePath}" --dir "${traceOutDir}"`);
|
|
568
|
+
assert.strictEqual(ingestRes.status, 0);
|
|
569
|
+
assert.match(ingestRes.stdout, /Production Trace Ingested into Harness² Regression Test/);
|
|
570
|
+
|
|
571
|
+
const generatedTask = path.join(traceOutDir, 'regression-trace-spark-oom.json');
|
|
572
|
+
assert.strictEqual(fs.existsSync(generatedTask), true);
|
|
573
|
+
const taskContent = JSON.parse(fs.readFileSync(generatedTask, 'utf8'));
|
|
574
|
+
assert.strictEqual(taskContent.id, 'regression-trace-spark-oom');
|
|
575
|
+
assert.strictEqual(taskContent.sourceTrace, 'production-failure.json');
|
|
576
|
+
assert.match(taskContent.errorCategory, /OutOfMemoryError/);
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
it('should display info for budget-guard lifecycle hook', () => {
|
|
580
|
+
const res = runCli('info budget-guard');
|
|
581
|
+
assert.strictEqual(res.status, 0);
|
|
582
|
+
assert.match(res.stdout, /budget-guard/);
|
|
583
|
+
assert.match(res.stdout, /PreToolUse/);
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
it('should display info for context-warmer skill and human-gate hook', () => {
|
|
587
|
+
const resSkill = runCli('info context-warmer');
|
|
588
|
+
assert.strictEqual(resSkill.status, 0);
|
|
589
|
+
assert.match(resSkill.stdout, /context-warmer/);
|
|
590
|
+
|
|
591
|
+
const resHook = runCli('info human-gate');
|
|
592
|
+
assert.strictEqual(resHook.status, 0);
|
|
593
|
+
assert.match(resHook.stdout, /human-gate/);
|
|
594
|
+
assert.match(resHook.stdout, /PreToolUse/);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
it('should display info for v2.2.0 skills (bigquery-vector-search, cloud-run-agents, pubsub-event-mesh, spanner-graph-rag)', () => {
|
|
598
|
+
for (const skill of ['bigquery-vector-search', 'cloud-run-agents', 'pubsub-event-mesh', 'spanner-graph-rag']) {
|
|
599
|
+
const res = runCli(`info ${skill}`);
|
|
600
|
+
assert.strictEqual(res.status, 0);
|
|
601
|
+
assert.match(res.stdout, new RegExp(skill));
|
|
602
|
+
}
|
|
478
603
|
});
|
|
479
604
|
|
|
480
605
|
} finally {
|