@indexnetwork/protocol 66.0.0-rc.635.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.cards.d.ts +5 -3
- package/dist/internal/opportunities/opportunity.cards.js +22 -6
- 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
|
}
|
|
@@ -60,9 +60,11 @@ export declare function presentOpportunityCard(deps: OpportunityCardsDeps, oppor
|
|
|
60
60
|
}): Promise<OpportunityCard | null>;
|
|
61
61
|
/**
|
|
62
62
|
* List the viewer's opportunities in the given statuses as presented cards,
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
63
|
+
* one card per counterpart. An accepted row keeps that person's slot over a
|
|
64
|
+
* newer pending or negotiating one, and a pending row this viewer already
|
|
65
|
+
* committed to keeps it over a newer unanswered one. Among the same rank,
|
|
66
|
+
* newest wins. A rejected or expired row never takes the slot from a live
|
|
67
|
+
* one. Cards whose presentation fails are dropped.
|
|
66
68
|
*
|
|
67
69
|
* @param deps - Database, cache, and presenter.
|
|
68
70
|
* @param input - Viewer, statuses, optional network/intent scope, limit, cache bypass, skeleton mode.
|
|
@@ -33,6 +33,20 @@ function counterpartUserIds(opportunity, viewerId) {
|
|
|
33
33
|
function viewerHasCommitted(opportunity, viewerId) {
|
|
34
34
|
return (opportunity.committedActorIds ?? []).includes(viewerId);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Which row keeps a person's single radar slot.
|
|
38
|
+
* Accepted first, then a pending row this viewer already committed to,
|
|
39
|
+
* then other live rows. Rejected and expired never take the slot from those.
|
|
40
|
+
*/
|
|
41
|
+
function counterpartSlotRank(opportunity, viewerId) {
|
|
42
|
+
if (opportunity.status === 'rejected' || opportunity.status === 'expired')
|
|
43
|
+
return 3;
|
|
44
|
+
if (opportunity.status === 'accepted')
|
|
45
|
+
return 0;
|
|
46
|
+
if (opportunity.status === 'pending' && viewerHasCommitted(opportunity, viewerId))
|
|
47
|
+
return 1;
|
|
48
|
+
return 2;
|
|
49
|
+
}
|
|
36
50
|
function stampViewerCommitted(card, viewerCommitted) {
|
|
37
51
|
return { ...card, viewerCommitted };
|
|
38
52
|
}
|
|
@@ -113,9 +127,11 @@ export async function presentOpportunityCard(deps, opportunity, viewerId, option
|
|
|
113
127
|
}
|
|
114
128
|
/**
|
|
115
129
|
* List the viewer's opportunities in the given statuses as presented cards,
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
130
|
+
* one card per counterpart. An accepted row keeps that person's slot over a
|
|
131
|
+
* newer pending or negotiating one, and a pending row this viewer already
|
|
132
|
+
* committed to keeps it over a newer unanswered one. Among the same rank,
|
|
133
|
+
* newest wins. A rejected or expired row never takes the slot from a live
|
|
134
|
+
* one. Cards whose presentation fails are dropped.
|
|
119
135
|
*
|
|
120
136
|
* @param deps - Database, cache, and presenter.
|
|
121
137
|
* @param input - Viewer, statuses, optional network/intent scope, limit, cache bypass, skeleton mode.
|
|
@@ -133,9 +149,9 @@ export async function listOpportunityCards(deps, input) {
|
|
|
133
149
|
const visible = raw
|
|
134
150
|
.filter((opp) => requested.has(opp.status) && canUserSeeOpportunity(opp.actors, opp.status, viewerId))
|
|
135
151
|
.sort((a, b) => {
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
return
|
|
152
|
+
const rank = counterpartSlotRank(a, viewerId) - counterpartSlotRank(b, viewerId);
|
|
153
|
+
if (rank !== 0)
|
|
154
|
+
return rank;
|
|
139
155
|
return b.createdAt.getTime() - a.createdAt.getTime();
|
|
140
156
|
});
|
|
141
157
|
const seen = new Set();
|
|
@@ -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.
|