activegraph 1.0.0__py3-none-any.whl

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.
Files changed (86) hide show
  1. activegraph/__init__.py +222 -0
  2. activegraph/__main__.py +5 -0
  3. activegraph/behaviors/__init__.py +1 -0
  4. activegraph/behaviors/base.py +153 -0
  5. activegraph/behaviors/decorators.py +218 -0
  6. activegraph/cli/__init__.py +17 -0
  7. activegraph/cli/main.py +793 -0
  8. activegraph/cli/quickstart.py +556 -0
  9. activegraph/core/__init__.py +1 -0
  10. activegraph/core/clock.py +46 -0
  11. activegraph/core/event.py +33 -0
  12. activegraph/core/graph.py +846 -0
  13. activegraph/core/ids.py +135 -0
  14. activegraph/core/patch.py +47 -0
  15. activegraph/core/view.py +59 -0
  16. activegraph/errors.py +345 -0
  17. activegraph/frame.py +15 -0
  18. activegraph/llm/__init__.py +51 -0
  19. activegraph/llm/anthropic.py +339 -0
  20. activegraph/llm/cache.py +180 -0
  21. activegraph/llm/errors.py +257 -0
  22. activegraph/llm/prompt.py +420 -0
  23. activegraph/llm/provider.py +66 -0
  24. activegraph/llm/recorded.py +270 -0
  25. activegraph/llm/types.py +130 -0
  26. activegraph/observability/__init__.py +61 -0
  27. activegraph/observability/logging.py +205 -0
  28. activegraph/observability/metrics.py +219 -0
  29. activegraph/observability/migration.py +404 -0
  30. activegraph/observability/prometheus.py +101 -0
  31. activegraph/observability/status.py +83 -0
  32. activegraph/packs/__init__.py +999 -0
  33. activegraph/packs/diligence/__init__.py +86 -0
  34. activegraph/packs/diligence/behaviors.py +447 -0
  35. activegraph/packs/diligence/fixtures/__init__.py +364 -0
  36. activegraph/packs/diligence/fixtures/companies.py +511 -0
  37. activegraph/packs/diligence/object_types.py +163 -0
  38. activegraph/packs/diligence/prompts/document_researcher.md +25 -0
  39. activegraph/packs/diligence/prompts/memo_synthesizer.md +35 -0
  40. activegraph/packs/diligence/prompts/question_generator.md +25 -0
  41. activegraph/packs/diligence/prompts/risk_identifier.md +26 -0
  42. activegraph/packs/diligence/settings.py +60 -0
  43. activegraph/packs/diligence/tools.py +124 -0
  44. activegraph/packs/loader.py +709 -0
  45. activegraph/packs/scaffold.py +317 -0
  46. activegraph/policy.py +20 -0
  47. activegraph/runtime/__init__.py +1 -0
  48. activegraph/runtime/behavior_graph.py +151 -0
  49. activegraph/runtime/budget.py +120 -0
  50. activegraph/runtime/config_errors.py +124 -0
  51. activegraph/runtime/diff.py +145 -0
  52. activegraph/runtime/errors.py +216 -0
  53. activegraph/runtime/exec_errors.py +232 -0
  54. activegraph/runtime/patterns.py +946 -0
  55. activegraph/runtime/queue.py +27 -0
  56. activegraph/runtime/registration_errors.py +291 -0
  57. activegraph/runtime/registry.py +111 -0
  58. activegraph/runtime/runtime.py +2441 -0
  59. activegraph/runtime/scheduler.py +206 -0
  60. activegraph/runtime/view_builder.py +65 -0
  61. activegraph/store/__init__.py +41 -0
  62. activegraph/store/base.py +66 -0
  63. activegraph/store/conformance.py +161 -0
  64. activegraph/store/errors.py +84 -0
  65. activegraph/store/memory.py +118 -0
  66. activegraph/store/postgres.py +609 -0
  67. activegraph/store/serde.py +202 -0
  68. activegraph/store/sqlite.py +446 -0
  69. activegraph/store/url.py +230 -0
  70. activegraph/tools/__init__.py +64 -0
  71. activegraph/tools/base.py +57 -0
  72. activegraph/tools/cache.py +157 -0
  73. activegraph/tools/context.py +48 -0
  74. activegraph/tools/decorators.py +70 -0
  75. activegraph/tools/errors.py +320 -0
  76. activegraph/tools/graph_query.py +94 -0
  77. activegraph/tools/recorded.py +205 -0
  78. activegraph/tools/web_fetch.py +80 -0
  79. activegraph/trace/__init__.py +1 -0
  80. activegraph/trace/causal.py +123 -0
  81. activegraph/trace/printer.py +495 -0
  82. activegraph-1.0.0.dist-info/METADATA +282 -0
  83. activegraph-1.0.0.dist-info/RECORD +86 -0
  84. activegraph-1.0.0.dist-info/WHEEL +5 -0
  85. activegraph-1.0.0.dist-info/entry_points.txt +5 -0
  86. activegraph-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,25 @@
1
+ ---
2
+ version = "1.0.0"
3
+ ---
4
+ You are a diligence researcher answering one question about a company.
5
+
6
+ Workflow:
7
+ 1. Call `fetch_company_docs` with the company name to obtain a list of
8
+ relevant source documents.
9
+ 2. Identify the most promising 1-2 documents for the question at hand.
10
+ 3. Call `summarize_document` on each to extract its summary and key
11
+ facts.
12
+ 4. From the extracted facts, formulate claims that answer the question.
13
+ For each claim:
14
+ - Write the claim in one sentence, verbatim where possible.
15
+ - Assign a confidence score (0.0-1.0) calibrated to evidence
16
+ strength. Below 0.5: rumor or weak inference. 0.5-0.7: plausible
17
+ but unverified. 0.7-0.9: well-supported by the document. 0.9+:
18
+ directly stated, primary source.
19
+ - Provide a verbatim evidence_quote — the exact sentence in the
20
+ document that supports the claim.
21
+
22
+ Do not invent claims. If a document does not address the question,
23
+ return an empty claims list and a summary that says so.
24
+
25
+ Return a single ResearchFindings object per the schema.
@@ -0,0 +1,35 @@
1
+ ---
2
+ version = "1.0.0"
3
+ ---
4
+ You are synthesizing the final diligence memo for a company.
5
+
6
+ The memo MUST have exactly these sections, in order:
7
+
8
+ 1. **summary**: 2-4 sentence executive summary. State the company,
9
+ the thesis question, and the bottom-line conclusion (or "open" if
10
+ unresolved).
11
+
12
+ 2. **thesis_questions_addressed**: a list, one entry per research
13
+ question with shape `{question, status, claim_ids}`. `status` is
14
+ "answered" or "unresolved". `claim_ids` lists the ids of claims
15
+ that address the question.
16
+
17
+ 3. **key_claims**: a list of the most material claims. Each entry has
18
+ shape `{claim_id, text, evidence_ids}`. Every claim entry MUST
19
+ include at least one evidence_id — uncited claims are not
20
+ permitted in the memo.
21
+
22
+ 4. **open_contradictions**: a list of unresolved contradictions, each
23
+ with shape `{contradiction_id, claim_a_text, claim_b_text}`. If
24
+ the run produced no contradictions, leave this list empty AND set
25
+ `contradictions_note` to the string "no contradictions found".
26
+
27
+ 5. **risks**: a list of the identified risks, each with shape
28
+ `{risk_id, title, severity, description}`. At least one risk MUST
29
+ be listed.
30
+
31
+ Read the graph view carefully — the data you need is all there. Do
32
+ not invent claims, evidence, contradictions, or risks. Use only
33
+ what the graph contains.
34
+
35
+ Return a single MemoBody object per the schema.
@@ -0,0 +1,25 @@
1
+ ---
2
+ version = "1.0.0"
3
+ ---
4
+ You are generating the initial research questions for an investment
5
+ diligence run on a single company.
6
+
7
+ Read the triggering event (a `company.created` event) and the view of
8
+ the graph (which contains the company object). Produce between
9
+ min_questions and max_questions distinct research questions that, if
10
+ answered, would constitute a thorough due-diligence picture of the
11
+ company.
12
+
13
+ Cover at least:
14
+ - Financial performance (revenue, margins, trajectory)
15
+ - Product (what they sell, how it's differentiated)
16
+ - Customers (segments, concentration, retention)
17
+ - Market (size, growth, competitive dynamics)
18
+ - Risks (regulatory, technological, executional)
19
+
20
+ Questions should be:
21
+ - Specific and answerable, not vague
22
+ - Each focused on one concern (no compound questions)
23
+ - Phrased so a researcher knows what document/source to consult
24
+
25
+ Return only the questions as a JSON list per the schema.
@@ -0,0 +1,26 @@
1
+ ---
2
+ version = "1.0.0"
3
+ ---
4
+ You are identifying material risks for a company based on its
5
+ accumulated claims.
6
+
7
+ You receive the graph view containing the company, its claims, the
8
+ documents those claims were derived from, and any detected
9
+ contradictions. Read all of it before responding.
10
+
11
+ For each risk you identify:
12
+ - Title: short noun phrase (e.g. "customer concentration", "regulatory
13
+ exposure to FDA action").
14
+ - Description: 1-3 sentences explaining the risk in concrete terms,
15
+ grounded in the observed claims.
16
+ - Severity: "low", "medium", or "high".
17
+ - related_claim_texts: list the verbatim text of the claims that
18
+ contribute to this risk. The handler will resolve these back to
19
+ claim ids; exact text match required.
20
+
21
+ Identify at least one risk per company. If a contradiction was
22
+ detected, it is itself a risk (severity at least "medium") and must
23
+ appear in your output. Material risks only — do not list every
24
+ hypothetical concern.
25
+
26
+ Return a RiskList object per the schema.
@@ -0,0 +1,60 @@
1
+ """Diligence pack settings. CONTRACT v0.9 #15.
2
+
3
+ Every field has a default so `runtime.load_pack(diligence_pack)`
4
+ without `settings=` works for the quickstart. The killer demo
5
+ overrides explicitly to demonstrate the typed-injection API.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from pydantic import BaseModel, Field
11
+
12
+
13
+ class DiligenceSettings(BaseModel):
14
+ """Configuration for the Diligence pack.
15
+
16
+ Accessed by behaviors in three forms (CONTRACT v0.9 #7):
17
+ 1. Typed parameter injection (primary):
18
+ `def claim_extractor(event, graph, ctx, out, *,
19
+ settings: DiligenceSettings): ...`
20
+ 2. `ctx.settings.confidence_threshold_for_review`
21
+ 3. `ctx.pack_settings("diligence")` for cross-pack lookups.
22
+ """
23
+
24
+ llm_model: str = Field(
25
+ default="claude-sonnet-4-5",
26
+ description="The Claude model used by all diligence LLM behaviors.",
27
+ )
28
+ max_documents_per_company: int = Field(
29
+ default=5, ge=1,
30
+ description="Cap on documents fetched per company. Bounds tool cost.",
31
+ )
32
+ max_claims_per_document: int = Field(
33
+ default=20, ge=1,
34
+ description="Cap on claims extracted per document. Bounds LLM cost and "
35
+ "downstream evidence-linking work.",
36
+ )
37
+ confidence_threshold_for_review: float = Field(
38
+ default=0.7, ge=0.0, le=1.0,
39
+ description="Claims with confidence ≥ this threshold participate in "
40
+ "contradiction detection.",
41
+ )
42
+ min_questions: int = Field(
43
+ default=8, ge=1,
44
+ description="Minimum number of thesis questions the generator produces.",
45
+ )
46
+ max_questions: int = Field(
47
+ default=15, ge=1,
48
+ description="Maximum number of thesis questions. Generator is one-shot "
49
+ "in v0.9 (CONTRACT v0.9 #16); adaptive in v1.0.",
50
+ )
51
+ auto_approve_memos: bool = Field(
52
+ default=True,
53
+ description="When False, memo writes go through the memo_approval "
54
+ "policy (CONTRACT v0.9 #15 / #9). True for quickstart.",
55
+ )
56
+ auto_approve_risks: bool = Field(
57
+ default=True,
58
+ description="When False, risk writes go through the risk_approval "
59
+ "policy. True for quickstart.",
60
+ )
@@ -0,0 +1,124 @@
1
+ """Diligence pack tools. CONTRACT v0.9 #15.
2
+
3
+ Three pack-scoped tools backed by recorded fixtures. Production users
4
+ swap these for real implementations:
5
+ - fetch_company_docs: would call a real fetcher (SEC, news APIs, etc.)
6
+ - search_filings: would query EDGAR or a similar service
7
+ - summarize_document: an LLM-backed summarizer with caching
8
+
9
+ The fixtures live in `activegraph.packs.diligence.fixtures` per
10
+ CONTRACT v0.9 #18 (fixtures ship with the pack).
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from decimal import Decimal
16
+ from typing import Optional
17
+
18
+ from pydantic import BaseModel
19
+
20
+ from activegraph.packs import tool
21
+
22
+
23
+ # ---------------------------------------------------- I/O schemas
24
+
25
+
26
+ class FetchCompanyDocsInput(BaseModel):
27
+ company_name: str
28
+ max_results: int = 5
29
+
30
+
31
+ class DocumentRef(BaseModel):
32
+ title: str
33
+ url: str
34
+ summary: str = ""
35
+
36
+
37
+ class FetchCompanyDocsOutput(BaseModel):
38
+ documents: list[DocumentRef]
39
+
40
+
41
+ class SearchFilingsInput(BaseModel):
42
+ company_name: str
43
+ keyword: str = ""
44
+
45
+
46
+ class SearchFilingsOutput(BaseModel):
47
+ filings: list[DocumentRef]
48
+
49
+
50
+ class SummarizeDocumentInput(BaseModel):
51
+ url: str
52
+ max_words: int = 100
53
+
54
+
55
+ class SummarizeDocumentOutput(BaseModel):
56
+ summary: str
57
+ extracted_facts: list[str] = []
58
+
59
+
60
+ # ---------------------------------------------------- tool registration
61
+
62
+
63
+ @tool(
64
+ name="fetch_company_docs",
65
+ description="Fetch a list of source documents for a company. "
66
+ "Returns up to max_results documents with title, URL, "
67
+ "and a one-line summary.",
68
+ input_schema=FetchCompanyDocsInput,
69
+ output_schema=FetchCompanyDocsOutput,
70
+ cost_per_call=Decimal("0.005"),
71
+ timeout_seconds=15.0,
72
+ deterministic=False,
73
+ )
74
+ def fetch_company_docs(args: FetchCompanyDocsInput, ctx) -> FetchCompanyDocsOutput:
75
+ """Backed by fixtures in v0.9. Production: real fetcher."""
76
+ from activegraph.packs.diligence.fixtures import lookup_company_docs
77
+
78
+ docs = lookup_company_docs(args.company_name, max_results=args.max_results)
79
+ return FetchCompanyDocsOutput(
80
+ documents=[DocumentRef(**d) for d in docs],
81
+ )
82
+
83
+
84
+ @tool(
85
+ name="search_filings",
86
+ description="Search a company's regulatory filings by keyword. "
87
+ "Returns matching filings as document refs.",
88
+ input_schema=SearchFilingsInput,
89
+ output_schema=SearchFilingsOutput,
90
+ cost_per_call=Decimal("0.003"),
91
+ timeout_seconds=15.0,
92
+ deterministic=False,
93
+ )
94
+ def search_filings(args: SearchFilingsInput, ctx) -> SearchFilingsOutput:
95
+ """Backed by fixtures in v0.9. Production: EDGAR query."""
96
+ from activegraph.packs.diligence.fixtures import lookup_filings
97
+
98
+ filings = lookup_filings(args.company_name, args.keyword)
99
+ return SearchFilingsOutput(
100
+ filings=[DocumentRef(**f) for f in filings],
101
+ )
102
+
103
+
104
+ @tool(
105
+ name="summarize_document",
106
+ description="Summarize a document at a given URL and extract key facts.",
107
+ input_schema=SummarizeDocumentInput,
108
+ output_schema=SummarizeDocumentOutput,
109
+ cost_per_call=Decimal("0.002"),
110
+ timeout_seconds=30.0,
111
+ deterministic=False,
112
+ )
113
+ def summarize_document(args: SummarizeDocumentInput, ctx) -> SummarizeDocumentOutput:
114
+ """Backed by fixtures in v0.9. Production: LLM summarizer."""
115
+ from activegraph.packs.diligence.fixtures import lookup_summary
116
+
117
+ result = lookup_summary(args.url)
118
+ return SummarizeDocumentOutput(
119
+ summary=result.get("summary", "")[: args.max_words * 8], # rough char cap
120
+ extracted_facts=result.get("facts", []),
121
+ )
122
+
123
+
124
+ TOOLS = [fetch_company_docs, search_filings, summarize_document]