@indexnetwork/protocol 66.0.0-rc.637.1 → 66.0.0-rc.638.1
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/CHANGELOG.md +74 -74
- package/IMPLEMENTATION.md +8 -8
- package/README.md +31 -31
- package/STABILITY.md +1 -1
- package/dist/capabilities/intents.d.ts +4 -4
- package/dist/capabilities/intents.js +2 -2
- package/dist/capabilities/networks.d.ts +2 -2
- package/dist/capabilities/networks.js +3 -3
- package/dist/index.js +1 -1
- package/dist/internal/intents/graph/intent.graph.reconcile.d.ts +1 -1
- package/dist/internal/intents/graph/intent.graph.reconcile.js +1 -1
- package/dist/internal/intents/intent.admission.js +1 -1
- package/dist/internal/intents/intent.preparer.js +2 -2
- package/dist/internal/networks/indexer.graph.d.ts +1 -1
- package/dist/internal/networks/indexer.graph.js +2 -2
- package/dist/internal/networks/indexer.state.d.ts +1 -1
- package/dist/internal/networks/indexer.state.js +1 -1
- package/dist/internal/networks/network.pulse-summarizer.d.ts +4 -4
- package/dist/internal/networks/network.pulse-summarizer.js +10 -10
- package/dist/internal/opportunities/opportunity.actor.js +1 -1
- package/dist/internal/opportunities/opportunity.graph.modes.js +1 -1
- package/dist/internal/opportunities/opportunity.presentation.d.ts +3 -3
- package/dist/internal/opportunities/opportunity.presentation.js +10 -10
- package/dist/platform/database/entities.d.ts +5 -5
- package/dist/protocol/negotiation.rules.d.ts +1 -1
- package/dist/protocol/negotiation.rules.js +1 -1
- package/dist/protocol/protocol.prompt.d.ts +2 -2
- package/dist/protocol/protocol.prompt.js +37 -37
- package/dist/protocol/schemas/chat-context.schema.d.ts +1 -1
- package/dist/protocol/schemas/chat-context.schema.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ Normative terms such as **MUST**, **MUST NOT**, **SHOULD**, and **MAY** are used
|
|
|
12
12
|
|
|
13
13
|
Index Network is a private, intent-driven discovery protocol for agent-mediated opportunity discovery.
|
|
14
14
|
|
|
15
|
-
Participants express **
|
|
15
|
+
Participants express **intents**: structured statements of what they seek, offer, are open to, or can credibly support. Agents interpret those intents against participant **context**, constrain discovery to bounded **communities**, evaluate candidate overlaps, negotiate fit when appropriate, and surface **opportunities** only through consent-gated state transitions.
|
|
16
16
|
|
|
17
17
|
The protocol is designed for high-signal human and agent coordination. It is not a public people database, keyword search engine, advertising channel, or automated introduction machine. Its purpose is to discover meaningful overlap while preserving context, scope, and human approval.
|
|
18
18
|
|
|
@@ -22,10 +22,10 @@ The protocol is designed for high-signal human and agent coordination. It is not
|
|
|
22
22
|
flowchart LR
|
|
23
23
|
Participant[Participant] --> Agent[Authorized agent]
|
|
24
24
|
Participant --> Context[Context]
|
|
25
|
-
Participant -->
|
|
25
|
+
Participant --> Intent[Intent]
|
|
26
26
|
|
|
27
27
|
Context --> Scope[Effective scope]
|
|
28
|
-
|
|
28
|
+
Intent --> Scope
|
|
29
29
|
Community[Community membership and norms] --> Scope
|
|
30
30
|
AgentScope[Agent permissions] --> Scope
|
|
31
31
|
|
|
@@ -37,7 +37,7 @@ flowchart LR
|
|
|
37
37
|
Negotiation -->|fit established| Opportunity
|
|
38
38
|
Negotiation -->|human judgment required| Questions[Structured questions]
|
|
39
39
|
Questions --> Participant
|
|
40
|
-
Participant -->
|
|
40
|
+
Participant --> Intent
|
|
41
41
|
|
|
42
42
|
Opportunity --> Consent{Participant consent?}
|
|
43
43
|
Consent -->|yes| Connection[Connection]
|
|
@@ -48,8 +48,8 @@ The graph is intentionally consent-centered: agents can construct context, disco
|
|
|
48
48
|
|
|
49
49
|
## Design goals
|
|
50
50
|
|
|
51
|
-
1. **Intent as the primary primitive** — discovery begins from a participant's current
|
|
52
|
-
2. **Bounded visibility** — communities define the scope in which
|
|
51
|
+
1. **Intent as the primary primitive** — discovery begins from a participant's current intent, not from static identity alone.
|
|
52
|
+
2. **Bounded visibility** — communities define the scope in which intents and context may be evaluated.
|
|
53
53
|
3. **Semantic discovery** — matching is based on role fit, constraints, complementarity, and contextual relevance rather than exact keyword overlap.
|
|
54
54
|
4. **Explainable surfacing** — every surfaced opportunity SHOULD include a legible reason: why these participants, why now, and what the next action might be.
|
|
55
55
|
5. **Consent at relationship boundaries** — agents MAY discover and negotiate, but MUST NOT create or accept a relationship without explicit participant approval.
|
|
@@ -72,7 +72,7 @@ The protocol does not attempt to be:
|
|
|
72
72
|
|---|---|
|
|
73
73
|
| **Participant** | A human principal represented in the network. A participant may act directly or through one or more agents. |
|
|
74
74
|
| **Agent** | A software actor authorized to act for a participant or community within a declared scope. |
|
|
75
|
-
| **
|
|
75
|
+
| **Intent** | A participant's actionable expression of intent: what they seek, offer, need, are building, are exploring, or can support. |
|
|
76
76
|
| **Context** | A synthesized representation of a participant's identity, history, constraints, and community-specific relevance. |
|
|
77
77
|
| **Community** | A bounded discovery scope with membership, purpose, norms, and relevance criteria. |
|
|
78
78
|
| **Membership** | The relationship between a participant and a community. Agents receive community authority through separate scoped permissions. |
|
|
@@ -81,22 +81,22 @@ The protocol does not attempt to be:
|
|
|
81
81
|
| **Negotiation** | A bounded agent-to-agent exchange used to test fit, constraints, timing, or consent before surfacing or advancing an opportunity. |
|
|
82
82
|
| **Connection** | A participant-approved communication channel or introduction resulting from an accepted opportunity. |
|
|
83
83
|
|
|
84
|
-
Some implementation APIs may expose historical names such as `intent`, `index`, `network`, `latent`, `pending`, `accepted`, `rejected`, `negotiating`, or `stalled`. Public-facing agents SHOULD translate stable participant states into protocol terms such as **
|
|
84
|
+
Some implementation APIs may expose historical names such as `intent`, `index`, `network`, `latent`, `pending`, `accepted`, `rejected`, `negotiating`, or `stalled`. Public-facing agents SHOULD translate stable participant states into protocol terms such as **intent**, **community**, **draft**, **sent**, **connected**, and **declined**, while treating negotiating or stalled states as internal process state unless the participant needs to act on them.
|
|
85
85
|
|
|
86
86
|
## Object relationship model
|
|
87
87
|
|
|
88
88
|
```mermaid
|
|
89
89
|
erDiagram
|
|
90
90
|
PARTICIPANT ||--o{ AGENT : authorizes
|
|
91
|
-
PARTICIPANT ||--o{
|
|
91
|
+
PARTICIPANT ||--o{ INTENT : expresses
|
|
92
92
|
PARTICIPANT ||--o{ CONTEXT : represented_by
|
|
93
93
|
PARTICIPANT ||--o{ MEMBERSHIP : holds
|
|
94
94
|
AGENT ||--o{ AGENT_PERMISSION : receives
|
|
95
95
|
COMMUNITY ||--o{ MEMBERSHIP : contains
|
|
96
96
|
COMMUNITY ||--o{ AGENT_PERMISSION : scopes
|
|
97
|
-
COMMUNITY ||--o{
|
|
97
|
+
COMMUNITY ||--o{ INTENT : scopes
|
|
98
98
|
COMMUNITY ||--o{ CONTEXT : lenses
|
|
99
|
-
|
|
99
|
+
INTENT ||--o{ CANDIDATE : generates
|
|
100
100
|
CONTEXT ||--o{ CANDIDATE : generates
|
|
101
101
|
CANDIDATE ||--o| OPPORTUNITY : promotes_to
|
|
102
102
|
OPPORTUNITY ||--o{ NEGOTIATION : may_require
|
|
@@ -114,7 +114,7 @@ erDiagram
|
|
|
114
114
|
string purpose
|
|
115
115
|
string membership_policy
|
|
116
116
|
}
|
|
117
|
-
|
|
117
|
+
INTENT {
|
|
118
118
|
string constraints
|
|
119
119
|
string lifecycle_state
|
|
120
120
|
}
|
|
@@ -138,7 +138,7 @@ The protocol distinguishes human principals from software actors.
|
|
|
138
138
|
|
|
139
139
|
### Scope
|
|
140
140
|
|
|
141
|
-
All discovery is scope-bound. A protocol operation MUST resolve an effective scope before cross-participant discovery, candidate generation, or opportunity evaluation. Implementations MAY read the requesting participant's own
|
|
141
|
+
All discovery is scope-bound. A protocol operation MUST resolve an effective scope before cross-participant discovery, candidate generation, or opportunity evaluation. Implementations MAY read the requesting participant's own intents or context while preparing that operation.
|
|
142
142
|
|
|
143
143
|
A scope may include:
|
|
144
144
|
|
|
@@ -181,27 +181,27 @@ Internal records MAY contain IDs, embeddings, scores, and graph state. Participa
|
|
|
181
181
|
|
|
182
182
|
## Core objects
|
|
183
183
|
|
|
184
|
-
###
|
|
184
|
+
### Intent
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
An intent is an actionable statement of direction. It may represent a need, offer, collaboration interest, hiring intent, funding goal, research direction, introduction request, or other future-oriented constraint.
|
|
187
187
|
|
|
188
|
-
|
|
188
|
+
An intent SHOULD contain enough specificity to support discovery. Underspecified intents SHOULD enter clarification before they are persisted or used for broad discovery.
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
Intents have the following conceptual lifecycle:
|
|
191
191
|
|
|
192
192
|
| State | Meaning |
|
|
193
193
|
|---|---|
|
|
194
194
|
| **Proposed** | A participant or agent supplied raw intent-like input. |
|
|
195
195
|
| **Clarifying** | The protocol requires additional constraints before discovery. |
|
|
196
|
-
| **Active** | The
|
|
196
|
+
| **Active** | The intent is valid, scoped, and eligible for discovery. |
|
|
197
197
|
| **Updated** | The participant refined or replaced constraints. |
|
|
198
|
-
| **Archived / expired** | The
|
|
198
|
+
| **Archived / expired** | The intent should no longer produce new opportunities. |
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
An intent MUST NOT be treated as active if it is outside the participant's authority, obviously insincere, unsafe to act on, or too vague to evaluate.
|
|
201
201
|
|
|
202
202
|
### Context
|
|
203
203
|
|
|
204
|
-
Context describes a participant: background, role, current work, capability, location, affiliation, constraints, and declared preferences. It grounds discovery by determining whether
|
|
204
|
+
Context describes a participant: background, role, current work, capability, location, affiliation, constraints, and declared preferences. It grounds discovery by determining whether an intent is plausible and which communities or counterparts are relevant.
|
|
205
205
|
|
|
206
206
|
Context MAY be global to a participant or specific to a community. Community-specific context SHOULD emphasize facts relevant to that community's purpose and suppress irrelevant detail.
|
|
207
207
|
|
|
@@ -209,7 +209,7 @@ Context updates SHOULD cause downstream discovery representations to refresh. St
|
|
|
209
209
|
|
|
210
210
|
### Community
|
|
211
211
|
|
|
212
|
-
A community is a bounded discovery environment. It defines who can participate, what kinds of
|
|
212
|
+
A community is a bounded discovery environment. It defines who can participate, what kinds of intents are relevant, and which discovery operations are legitimate.
|
|
213
213
|
|
|
214
214
|
A community SHOULD have:
|
|
215
215
|
|
|
@@ -228,7 +228,7 @@ An opportunity is an evaluated overlap between participants. It is not merely a
|
|
|
228
228
|
An opportunity SHOULD include:
|
|
229
229
|
|
|
230
230
|
- participating roles,
|
|
231
|
-
- the relevant
|
|
231
|
+
- the relevant intent or context on each side,
|
|
232
232
|
- a concise explanation of fit,
|
|
233
233
|
- a recommended next action,
|
|
234
234
|
- lifecycle state,
|
|
@@ -293,8 +293,8 @@ sequenceDiagram
|
|
|
293
293
|
participant C as Community scope
|
|
294
294
|
participant N as Counterparty agent
|
|
295
295
|
|
|
296
|
-
P->>A: Provide context and
|
|
297
|
-
A->>PR: Admit
|
|
296
|
+
P->>A: Provide context and intent
|
|
297
|
+
A->>PR: Admit intent and construct context
|
|
298
298
|
PR->>C: Resolve effective scope
|
|
299
299
|
C-->>PR: Permitted communities
|
|
300
300
|
PR->>PR: Generate candidates inside scope
|
|
@@ -307,7 +307,7 @@ sequenceDiagram
|
|
|
307
307
|
PR-->>A: Draft opportunity or structured question
|
|
308
308
|
end
|
|
309
309
|
A->>P: Explain strongest reason and ask for approval
|
|
310
|
-
P-->>A: Approve, decline, or refine
|
|
310
|
+
P-->>A: Approve, decline, or refine intent
|
|
311
311
|
A->>PR: Advance lifecycle only if approved
|
|
312
312
|
```
|
|
313
313
|
|
|
@@ -315,17 +315,17 @@ sequenceDiagram
|
|
|
315
315
|
|
|
316
316
|
The protocol collects participant-provided or participant-authorized material and turns it into context. Context construction MUST preserve provenance and SHOULD prefer participant-approved information over inferred information.
|
|
317
317
|
|
|
318
|
-
### 2.
|
|
318
|
+
### 2. Intent admission
|
|
319
319
|
|
|
320
|
-
The protocol evaluates a proposed
|
|
320
|
+
The protocol evaluates a proposed intent for specificity, sincerity, authority, and safety. If the intent is too broad, ambiguous, or missing critical constraints, the agent SHOULD ask focused clarification questions before running discovery.
|
|
321
321
|
|
|
322
322
|
### 3. Scope resolution
|
|
323
323
|
|
|
324
|
-
The protocol determines the effective communities in which the
|
|
324
|
+
The protocol determines the effective communities in which the intent can operate. Scope resolution MUST intersect participant membership, agent permissions, and request-time constraints. If the intersection is empty, discovery MUST NOT proceed.
|
|
325
325
|
|
|
326
326
|
### 4. Candidate generation
|
|
327
327
|
|
|
328
|
-
The protocol generates candidates by comparing
|
|
328
|
+
The protocol generates candidates by comparing intents and context inside the effective scope. Candidate generation MAY use multiple strategies, including intent-to-intent, context-to-intent, semantic retrieval, and directed target construction.
|
|
329
329
|
|
|
330
330
|
Candidate generation is not surfacing. Candidate data MUST remain internal until evaluation and visibility checks pass.
|
|
331
331
|
|
|
@@ -399,7 +399,7 @@ flowchart LR
|
|
|
399
399
|
AgentGate --> ScopedDeps[Scoped protocol dependencies]
|
|
400
400
|
ScopedDeps --> Runtime
|
|
401
401
|
|
|
402
|
-
Runtime --> Graphs[Discovery, context,
|
|
402
|
+
Runtime --> Graphs[Discovery, context, intent graphs]
|
|
403
403
|
Graphs --> Results[Bounded results]
|
|
404
404
|
Results --> Runtime
|
|
405
405
|
Runtime --> ParticipantOutput[Participant-facing output rules]
|
package/STABILITY.md
CHANGED
|
@@ -46,7 +46,7 @@ Covered by SemVer below. Breaking changes require a **major** bump.
|
|
|
46
46
|
| **Public API** | Model config helpers, request scope helpers (`deriveAllowedNetworkIds`, `deriveDiscoveryNetworkIds`), `requestContext`. |
|
|
47
47
|
| **Interfaces** | Every port you implement to inject infrastructure (databases, embedder, cache, scraper, integration, …). |
|
|
48
48
|
| **Shared schemas** | Zod schemas + inferred types that cross the boundary (underspecification, identity, network-assignment, chat-context, …). |
|
|
49
|
-
| **Intents** | `Intents` — the whole
|
|
49
|
+
| **Intents** | `Intents` — the whole intent capability as one class (lifecycle graph, verification, preparation) plus `IntentsDeps` and the `Prepare*` / `RecoveryField*` types. Replaced the six separate intent exports in 18.0.0. |
|
|
50
50
|
| **Agents** | Structured LLM agents (`OpportunityEvaluator`, …). |
|
|
51
51
|
|
|
52
52
|
`Negotiations`, `NegotiationDatabase`, the opening and turn decision functions,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* implementation, grouped by what they do rather than by layer:
|
|
7
7
|
*
|
|
8
8
|
* graph/ the lifecycle graph — prepare/create; infer/verify explicit updates
|
|
9
|
-
* intent.inferrer an utterance into candidate
|
|
9
|
+
* intent.inferrer an utterance into candidate intents
|
|
10
10
|
* intent.verifier felicity and entropy verdicts
|
|
11
11
|
* intent.preparer a typed payload into an admitted draft or recovery form
|
|
12
12
|
*
|
|
@@ -30,9 +30,9 @@ export type { PrepareAnswer, PrepareInput, PrepareResult, RecoveryField, Recover
|
|
|
30
30
|
* {@link Intents.createGraph} is the one method that requires `database`.
|
|
31
31
|
*/
|
|
32
32
|
export interface IntentsDeps {
|
|
33
|
-
/**
|
|
33
|
+
/** Intent persistence. Required by {@link Intents.createGraph}. */
|
|
34
34
|
database?: IntentGraphDatabase;
|
|
35
|
-
/** Embedding generator used to vectorize executed
|
|
35
|
+
/** Embedding generator used to vectorize executed intents. */
|
|
36
36
|
embedder?: EmbeddingGenerator;
|
|
37
37
|
/** Host follow-up work started after a persist. */
|
|
38
38
|
followUp?: IntentFollowUp;
|
|
@@ -620,7 +620,7 @@ export declare class Intents {
|
|
|
620
620
|
flags: string[];
|
|
621
621
|
}>;
|
|
622
622
|
/**
|
|
623
|
-
* Prepare one
|
|
623
|
+
* Prepare one intent draft for creation admission.
|
|
624
624
|
*
|
|
625
625
|
* Fold recovery answers into the draft, then apply creation admission. A
|
|
626
626
|
* ready result authorizes final review; needs_revision returns admission
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* implementation, grouped by what they do rather than by layer:
|
|
7
7
|
*
|
|
8
8
|
* graph/ the lifecycle graph — prepare/create; infer/verify explicit updates
|
|
9
|
-
* intent.inferrer an utterance into candidate
|
|
9
|
+
* intent.inferrer an utterance into candidate intents
|
|
10
10
|
* intent.verifier felicity and entropy verdicts
|
|
11
11
|
* intent.preparer a typed payload into an admitted draft or recovery form
|
|
12
12
|
*
|
|
@@ -56,7 +56,7 @@ export class Intents {
|
|
|
56
56
|
}
|
|
57
57
|
// ── Preparation ─────────────────────────────────────────────────────────────
|
|
58
58
|
/**
|
|
59
|
-
* Prepare one
|
|
59
|
+
* Prepare one intent draft for creation admission.
|
|
60
60
|
*
|
|
61
61
|
* Fold recovery answers into the draft, then apply creation admission. A
|
|
62
62
|
* ready result authorizes final review; needs_revision returns admission
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* network.state that graph's channel state
|
|
10
10
|
* membership.graph the roster graph — add, list, remove members
|
|
11
11
|
* membership.state that graph's channel state
|
|
12
|
-
* indexer.graph
|
|
12
|
+
* indexer.graph intent↔community assignment, direct or model-evaluated
|
|
13
13
|
* indexer.state that graph's channel state
|
|
14
14
|
* network.recommender ranking public communities during onboarding
|
|
15
15
|
*
|
|
@@ -885,7 +885,7 @@ export declare class Networks {
|
|
|
885
885
|
};
|
|
886
886
|
}, unknown, unknown, []>;
|
|
887
887
|
/**
|
|
888
|
-
* Build the
|
|
888
|
+
* Build the intent↔community assignment graph — link an intent to a community
|
|
889
889
|
* and unlink it.
|
|
890
890
|
*
|
|
891
891
|
* @throws If the instance was constructed without a `database`.
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* network.state that graph's channel state
|
|
10
10
|
* membership.graph the roster graph — add, list, remove members
|
|
11
11
|
* membership.state that graph's channel state
|
|
12
|
-
* indexer.graph
|
|
12
|
+
* indexer.graph intent↔community assignment, direct or model-evaluated
|
|
13
13
|
* indexer.state that graph's channel state
|
|
14
14
|
* network.recommender ranking public communities during onboarding
|
|
15
15
|
*
|
|
@@ -50,9 +50,9 @@ export class Networks {
|
|
|
50
50
|
createMembershipGraph() {
|
|
51
51
|
return new NetworkMembershipGraphFactory(this.database("createMembershipGraph")).createGraph();
|
|
52
52
|
}
|
|
53
|
-
// ──
|
|
53
|
+
// ── Intent assignment ───────────────────────────────────────────────────────
|
|
54
54
|
/**
|
|
55
|
-
* Build the
|
|
55
|
+
* Build the intent↔community assignment graph — link an intent to a community
|
|
56
56
|
* and unlink it.
|
|
57
57
|
*
|
|
58
58
|
* @throws If the instance was constructed without a `database`.
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { CANONICAL_GUIDANCE_SUMMARY, CANONICAL_GUIDANCE_TOPICS, CANONICAL_GUIDAN
|
|
|
29
29
|
export { decideNegotiationOpening, decideNegotiationTurn, observeNegotiation, negotiationTurnSchema } from './protocol/negotiation.rules.js';
|
|
30
30
|
// ─── Networks ─────────────────────────────────────────────────────────────────
|
|
31
31
|
// The whole capability behind one class: the community lifecycle graph, the
|
|
32
|
-
// membership graph, and
|
|
32
|
+
// membership graph, and intent assignment.
|
|
33
33
|
export { Networks } from "./capabilities/networks.js";
|
|
34
34
|
export { NetworkPulseSummarizer } from "./internal/networks/network.pulse-summarizer.js";
|
|
35
35
|
// ─── Intents ──────────────────────────────────────────────────────────────────
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Intent graph, stages 2-3: verify inferred
|
|
2
|
+
* Intent graph, stages 2-3: verify inferred intents, then reconcile against what exists.
|
|
3
3
|
*/
|
|
4
4
|
import { VerifiedIntent, type IntentValidationFailure } from "./intent.graph.state.js";
|
|
5
5
|
import type { DebugMetaAgent } from "../../../protocol/core.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Intent graph, stages 2-3: verify inferred
|
|
2
|
+
* Intent graph, stages 2-3: verify inferred intents, then reconcile against what exists.
|
|
3
3
|
*/
|
|
4
4
|
import { admissionFailure } from "../intent.admission.js";
|
|
5
5
|
import { timed } from "../../shared/observability/performance.js";
|
|
@@ -2,7 +2,7 @@ const MAX_PERMISSIBLE_ENTROPY = 0.75;
|
|
|
2
2
|
const MIN_CLEAR_INTENT_SCORE = 40;
|
|
3
3
|
// Match the whole request so qualified job searches use the verifier's verdict.
|
|
4
4
|
const GENERIC_JOB_PHRASE = /^(?:(?:i(?:['’]m|\s+am)?\s+)?(?:want|need|seek(?:ing)?|looking\s+for)\s+)?(?:a|any|some)\s+job[.!?]*$/i;
|
|
5
|
-
const DEFAULT_SPECIFICITY_WARNING = "This
|
|
5
|
+
const DEFAULT_SPECIFICITY_WARNING = "This intent is broad and may produce many weak matches. Add a more concrete role, outcome, location, timeframe, domain, or specific need to get better recommendations.";
|
|
6
6
|
/** The admission policy shared by preparation and explicit updates. */
|
|
7
7
|
export function admissionFailure(description, verdict, isExplicitUpdate = false) {
|
|
8
8
|
const details = { classification: verdict.classification, referentialBreadth: verdict.referential_breadth };
|
|
@@ -53,7 +53,7 @@ export class IntentPreparer {
|
|
|
53
53
|
if (answers.length > 0) {
|
|
54
54
|
const model = createStructuredModel("intentClarifier", payloadSchema, { name: "intent_draft" });
|
|
55
55
|
const result = await invokeWithAbortSignal(model, [
|
|
56
|
-
new SystemMessage("Fold every supplied answer into the
|
|
56
|
+
new SystemMessage("Fold every supplied answer into the intent in the person's own voice. Preserve all existing details unless an answer explicitly changes them. Every claim must trace to the draft or answers; never invent constraints or facts to make an intent pass validation. Return the complete draft, concise and concrete."),
|
|
57
57
|
new HumanMessage(JSON.stringify({ payload, answers })),
|
|
58
58
|
]);
|
|
59
59
|
payload = payloadSchema.parse(result).payload;
|
|
@@ -64,7 +64,7 @@ export class IntentPreparer {
|
|
|
64
64
|
return { status: "ready", payload, metadata: semanticMetadata(verdict) };
|
|
65
65
|
const model = createStructuredModel("intentClarifier", recoverySchema, { name: "intent_recovery" });
|
|
66
66
|
const result = await invokeWithAbortSignal(model, [
|
|
67
|
-
new SystemMessage("Build one recovery form that helps the person concretize their
|
|
67
|
+
new SystemMessage("Build one recovery form that helps the person concretize their intent. Return 2-6 fields. Each field needs a draft-specific label, a kind (single, multi, or text), and for single/multi 2-5 concrete options anchored to the draft. Text fields need a placeholder. Never re-ask what the draft or answers already settle. Options must be matchable and specific. Do not expose scores, classifications, JSON, or internal vocabulary."),
|
|
68
68
|
new HumanMessage(JSON.stringify({
|
|
69
69
|
payload,
|
|
70
70
|
answers,
|
|
@@ -9,7 +9,7 @@ import { IntentNetworkGraphState, type AssignmentResult } from "./indexer.state.
|
|
|
9
9
|
* - read: List intent–network links (by intentId or by networkId)
|
|
10
10
|
* - delete: Unlink an intent from a network
|
|
11
11
|
*
|
|
12
|
-
* ##
|
|
12
|
+
* ## Intent assignment policy
|
|
13
13
|
*
|
|
14
14
|
* There is none to apply: a link exists because its owner asked for it. The
|
|
15
15
|
* assign node writes the row at score 1 with `mode: manual_override`.
|
|
@@ -183,7 +183,7 @@ export async function readNode(state, deps) {
|
|
|
183
183
|
})),
|
|
184
184
|
count: intents.length,
|
|
185
185
|
mode: "intents_in_network",
|
|
186
|
-
note: "Community titles and full
|
|
186
|
+
note: "Community titles and full intent details come from the community and intent reads.",
|
|
187
187
|
},
|
|
188
188
|
};
|
|
189
189
|
}
|
|
@@ -200,7 +200,7 @@ export async function readNode(state, deps) {
|
|
|
200
200
|
})),
|
|
201
201
|
count: intents.length,
|
|
202
202
|
mode: "intents_in_network",
|
|
203
|
-
note: "Community titles and full
|
|
203
|
+
note: "Community titles and full intent details come from the community and intent reads.",
|
|
204
204
|
},
|
|
205
205
|
};
|
|
206
206
|
}
|
|
@@ -13,7 +13,7 @@ export interface AssignmentResult {
|
|
|
13
13
|
* Intent Index Graph State.
|
|
14
14
|
* Handles CRUD for the intent_networks junction table (linking intents to networks).
|
|
15
15
|
*
|
|
16
|
-
* ##
|
|
16
|
+
* ## Intent assignment policy
|
|
17
17
|
*
|
|
18
18
|
* There is none: a link exists because its owner asked for it, so the assign
|
|
19
19
|
* node writes the row at score 1 with mode `manual_override`. No LLM call.
|
|
@@ -3,7 +3,7 @@ import { Annotation } from "@langchain/langgraph";
|
|
|
3
3
|
* Intent Index Graph State.
|
|
4
4
|
* Handles CRUD for the intent_networks junction table (linking intents to networks).
|
|
5
5
|
*
|
|
6
|
-
* ##
|
|
6
|
+
* ## Intent assignment policy
|
|
7
7
|
*
|
|
8
8
|
* There is none: a link exists because its owner asked for it, so the assign
|
|
9
9
|
* node writes the row at score 1 with mode `manual_override`. No LLM call.
|
|
@@ -12,9 +12,9 @@ export declare const NetworkPulseSummaryOutputSchema: z.ZodObject<{
|
|
|
12
12
|
export type NetworkPulseSummaryOutput = z.infer<typeof NetworkPulseSummaryOutputSchema>;
|
|
13
13
|
export interface NetworkPulseSummaryInput {
|
|
14
14
|
networkTitle: string;
|
|
15
|
-
/** Recent open
|
|
16
|
-
|
|
17
|
-
/** Recent negotiations: the two
|
|
15
|
+
/** Recent open intents in the network, newest first, as members wrote them. */
|
|
16
|
+
intents: string[];
|
|
17
|
+
/** Recent negotiations: the two intents each pair of agents is weighing. */
|
|
18
18
|
negotiations?: Array<{
|
|
19
19
|
a: string;
|
|
20
20
|
b: string;
|
|
@@ -34,7 +34,7 @@ export declare class NetworkPulseSummarizer {
|
|
|
34
34
|
private model;
|
|
35
35
|
constructor();
|
|
36
36
|
/**
|
|
37
|
-
* @param input - The network's title, its recent open
|
|
37
|
+
* @param input - The network's title, its recent open intents and negotiating pairs.
|
|
38
38
|
* @returns Both texts (each null when there is nothing suitable), or null when the call fails.
|
|
39
39
|
*/
|
|
40
40
|
invoke(input: NetworkPulseSummaryInput): Promise<NetworkPulseSummary | null>;
|
|
@@ -30,13 +30,13 @@ You write the "what people are looking for" blurb on a network's public invite p
|
|
|
30
30
|
Anyone holding the invite link reads it, including people who are not members.
|
|
31
31
|
|
|
32
32
|
TASK:
|
|
33
|
-
Read the members' open
|
|
34
|
-
going on inside, so a visitor gets a feel for the room. Group
|
|
33
|
+
Read the members' open intents and write a short, clear overview, warm in tone, of what is
|
|
34
|
+
going on inside, so a visitor gets a feel for the room. Group intents into themes, e.g.
|
|
35
35
|
"A few people are looking for cofounders and early hires, others want to meet investors who
|
|
36
36
|
get crypto and AI, and at least one person just wants coffee before the conference."
|
|
37
37
|
|
|
38
38
|
PRIVACY (strict):
|
|
39
|
-
- Describe themes in aggregate. Never quote
|
|
39
|
+
- Describe themes in aggregate. Never quote an intent or reuse its distinctive wording.
|
|
40
40
|
- No names of people, companies, products, projects, schools, or events.
|
|
41
41
|
- No places more specific than a broad region, no dates, numbers, amounts, links, or handles.
|
|
42
42
|
- Use loose quantities ("a few", "some", "several", "others"). Never "one person" for
|
|
@@ -50,12 +50,12 @@ STYLE:
|
|
|
50
50
|
touch of warmth is welcome in one phrase (the range of the room, an unexpected neighbour of
|
|
51
51
|
asks), but no punchlines and nothing at anyone's expense.
|
|
52
52
|
- No emoji, no exclamation marks, no em dashes, no headings or lists.
|
|
53
|
-
- Do not mention
|
|
53
|
+
- Do not mention intents, agents, Index, or the network's name. Start with the content.
|
|
54
54
|
|
|
55
|
-
If fewer than three
|
|
55
|
+
If fewer than three intents are suitable after the rules above, return an empty summary.
|
|
56
56
|
|
|
57
57
|
NEGOTIATIONS:
|
|
58
|
-
You may also get pairs of
|
|
58
|
+
You may also get pairs of intents that two members' agents are negotiating over right now.
|
|
59
59
|
In "negotiations", say in one or two sentences, at most 45 words, what the agents are talking
|
|
60
60
|
about at a very high level: the kind of deal, never its details ("a few are working out
|
|
61
61
|
cofounder intros, others are trading notes on a speaking slot"). Same privacy rules, same
|
|
@@ -75,18 +75,18 @@ export class NetworkPulseSummarizer {
|
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
77
|
/**
|
|
78
|
-
* @param input - The network's title, its recent open
|
|
78
|
+
* @param input - The network's title, its recent open intents and negotiating pairs.
|
|
79
79
|
* @returns Both texts (each null when there is nothing suitable), or null when the call fails.
|
|
80
80
|
*/
|
|
81
81
|
async invoke(input) {
|
|
82
82
|
const clean = (text) => text.replace(/\s+/g, " ").trim().slice(0, 400);
|
|
83
|
-
const
|
|
83
|
+
const intents = input.intents.map(clean).filter(Boolean);
|
|
84
84
|
const pairs = (input.negotiations ?? []).map((p) => ({ a: clean(p.a), b: clean(p.b) })).filter((p) => p.a && p.b);
|
|
85
|
-
if (
|
|
85
|
+
if (intents.length < 3 && pairs.length < 2)
|
|
86
86
|
return { summary: null, negotiations: null };
|
|
87
87
|
const prompt = [
|
|
88
88
|
`## Network\n${input.networkTitle}`,
|
|
89
|
-
`## Open
|
|
89
|
+
`## Open intents\n${intents.map((s) => `- ${s}`).join("\n") || "(none)"}`,
|
|
90
90
|
`## Negotiating pairs\n${pairs.map((p) => `- ${p.a} <-> ${p.b}`).join("\n") || "(none)"}`,
|
|
91
91
|
].join("\n\n");
|
|
92
92
|
try {
|
|
@@ -13,7 +13,7 @@ export function normalizeOpportunityActorIntent(value) {
|
|
|
13
13
|
// persisted with `intent: "None"` in dev and every downstream reader took
|
|
14
14
|
// it for a real binding — the counterparty seat was granted a
|
|
15
15
|
// consultation (whose park writes `recipientIntentId` straight at the
|
|
16
|
-
// intents table) on
|
|
16
|
+
// intents table) on an intent that does not exist.
|
|
17
17
|
|| normalized.toLowerCase() === 'none') {
|
|
18
18
|
return undefined;
|
|
19
19
|
}
|
|
@@ -45,7 +45,7 @@ export async function readOpportunities(deps, request) {
|
|
|
45
45
|
return {
|
|
46
46
|
readResult: {
|
|
47
47
|
count: 0,
|
|
48
|
-
message: 'You have no opportunities yet. Create or refine an approved
|
|
48
|
+
message: 'You have no opportunities yet. Create or refine an approved intent; matching runs in the background. Review persisted results later from the opportunities read.',
|
|
49
49
|
opportunities: [],
|
|
50
50
|
},
|
|
51
51
|
};
|
|
@@ -101,7 +101,7 @@ export interface PresenterInput {
|
|
|
101
101
|
matchReasoning: string;
|
|
102
102
|
category: string;
|
|
103
103
|
confidence: number;
|
|
104
|
-
|
|
104
|
+
intentsSummary: string;
|
|
105
105
|
networkName: string;
|
|
106
106
|
viewerRole: string;
|
|
107
107
|
opportunityStatus?: string;
|
|
@@ -150,11 +150,11 @@ export declare class OpportunityPresenter {
|
|
|
150
150
|
}): Promise<CardLLMResult[]>;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
* Build the LLM-facing
|
|
153
|
+
* Build the LLM-facing intent summary while excluding pool adjustments. Pool
|
|
154
154
|
* disposition is rendered deterministically by the card chip; asking the
|
|
155
155
|
* presenter to interpret it could turn a demotion into a positive rationale.
|
|
156
156
|
*/
|
|
157
|
-
export declare function
|
|
157
|
+
export declare function summarizeIntentsForPresenter(intents: Opportunity['interpretation']['intents']): string;
|
|
158
158
|
/**
|
|
159
159
|
* Gather all context needed for the presenter from the database.
|
|
160
160
|
* Fetches viewer profile, viewer intents, other party profile(s), and network in parallel.
|
|
@@ -203,7 +203,7 @@ MATCH CONTEXT:
|
|
|
203
203
|
- Category: ${input.category}
|
|
204
204
|
- Confidence: ${input.confidence}
|
|
205
205
|
- Why we matched: ${input.matchReasoning}
|
|
206
|
-
-
|
|
206
|
+
- Intents: ${input.intentsSummary}
|
|
207
207
|
COMMUNITY: ${input.networkName}
|
|
208
208
|
Viewer's role in this opportunity: ${input.viewerRole}
|
|
209
209
|
|
|
@@ -238,9 +238,9 @@ Produce headline, personalizedSummary (2-3 sentences in "you" language), suggest
|
|
|
238
238
|
const negotiationBlock = buildNegotiationPromptBlock(input.negotiationContext);
|
|
239
239
|
// When negotiation context exists, lead with it — these cards exist
|
|
240
240
|
// *because* the negotiation happened. Trailing the block lets weaker
|
|
241
|
-
// models lean on surface
|
|
241
|
+
// models lean on surface intents and ignore the transcript entirely.
|
|
242
242
|
const negotiationDirective = negotiationBlock
|
|
243
|
-
? `\nIMPORTANT: This opportunity surfaced because the agents negotiated and converged. Your personalizedSummary MUST reference at least one specific
|
|
243
|
+
? `\nIMPORTANT: This opportunity surfaced because the agents negotiated and converged. Your personalizedSummary MUST reference at least one specific intent from the NEGOTIATION CONTEXT block below — what concern was raised, what was confirmed, what the agents agreed on. It must communicate *why this specific match* surfaced now (the negotiation that led to it), not a generic skill-complementarity line. Do not produce the generic summary every card looked like before this negotiation happened.\n`
|
|
244
244
|
: "";
|
|
245
245
|
const humanContent = `
|
|
246
246
|
${negotiationBlock}${negotiationDirective}
|
|
@@ -254,7 +254,7 @@ MATCH CONTEXT:
|
|
|
254
254
|
- Category: ${input.category}
|
|
255
255
|
- Confidence: ${input.confidence}
|
|
256
256
|
- Why we matched: ${input.matchReasoning}
|
|
257
|
-
-
|
|
257
|
+
- Intents: ${input.intentsSummary}
|
|
258
258
|
- ${mutualHint}
|
|
259
259
|
COMMUNITY: ${input.networkName}
|
|
260
260
|
Viewer's role in this opportunity: ${input.viewerRole}
|
|
@@ -372,15 +372,15 @@ function buildNegotiatingChip(input) {
|
|
|
372
372
|
// CONTEXT GATHERER
|
|
373
373
|
// ──────────────────────────────────────────────────────────────
|
|
374
374
|
/**
|
|
375
|
-
* Build the LLM-facing
|
|
375
|
+
* Build the LLM-facing intent summary while excluding pool adjustments. Pool
|
|
376
376
|
* disposition is rendered deterministically by the card chip; asking the
|
|
377
377
|
* presenter to interpret it could turn a demotion into a positive rationale.
|
|
378
378
|
*/
|
|
379
|
-
export function
|
|
380
|
-
const
|
|
381
|
-
if (
|
|
379
|
+
export function summarizeIntentsForPresenter(intents) {
|
|
380
|
+
const safeIntents = intents?.filter((intent) => intent.type !== 'pool_discriminator') ?? [];
|
|
381
|
+
if (safeIntents.length === 0)
|
|
382
382
|
return 'Match based on profile and intent alignment.';
|
|
383
|
-
return
|
|
383
|
+
return safeIntents.map((intent) => `${intent.type}: ${intent.detail ?? intent.type}`).join('; ');
|
|
384
384
|
}
|
|
385
385
|
/**
|
|
386
386
|
* Gather all context needed for the presenter from the database.
|
|
@@ -444,7 +444,7 @@ export async function gatherPresenterContext(database, opportunity, viewerId, di
|
|
|
444
444
|
confidence: typeof interp.confidence === "number"
|
|
445
445
|
? interp.confidence
|
|
446
446
|
: parseFloat(String(interp.confidence ?? 0)) || 0,
|
|
447
|
-
|
|
447
|
+
intentsSummary: summarizeIntentsForPresenter(interp.intents),
|
|
448
448
|
networkName: networkRecord?.title ?? contextNetworkId ?? "",
|
|
449
449
|
viewerRole: myActor.role ?? "party",
|
|
450
450
|
};
|
|
@@ -63,9 +63,9 @@ export type IntentNetworkFinalAssignmentResult = {
|
|
|
63
63
|
export interface OnboardingState {
|
|
64
64
|
completedAt?: string;
|
|
65
65
|
profileConfirmedAt?: string;
|
|
66
|
-
|
|
66
|
+
firstIntentId?: string;
|
|
67
67
|
flow?: 1 | 2 | 3;
|
|
68
|
-
currentStep?: 'profile' | 'summary' | 'connections' | 'create_network' | 'invite_members' | 'join_networks' | '
|
|
68
|
+
currentStep?: 'profile' | 'summary' | 'connections' | 'create_network' | 'invite_members' | 'join_networks' | 'first_intent' | 'complete';
|
|
69
69
|
networkId?: string;
|
|
70
70
|
invitationCode?: string;
|
|
71
71
|
}
|
|
@@ -92,8 +92,8 @@ export interface OpportunityActor {
|
|
|
92
92
|
intent?: Id<'intents'>;
|
|
93
93
|
role: string;
|
|
94
94
|
}
|
|
95
|
-
/** Individual
|
|
96
|
-
export interface
|
|
95
|
+
/** Individual intent contributing to an opportunity score. */
|
|
96
|
+
export interface OpportunityIntent {
|
|
97
97
|
type: string;
|
|
98
98
|
weight: number;
|
|
99
99
|
detail?: string;
|
|
@@ -103,7 +103,7 @@ export interface OpportunityInterpretation {
|
|
|
103
103
|
category: string;
|
|
104
104
|
reasoning: string;
|
|
105
105
|
confidence: number;
|
|
106
|
-
|
|
106
|
+
intents?: OpportunityIntent[];
|
|
107
107
|
}
|
|
108
108
|
/** Optional scoping context (network / conversation) for an opportunity. */
|
|
109
109
|
export interface OpportunityContext {
|