@indexnetwork/protocol 20.0.0-rc.484.1 → 21.0.0-rc.486.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/IMPLEMENTATION.md +1 -1
  3. package/dist/agents/index.d.ts +0 -1
  4. package/dist/agents/index.js +0 -1
  5. package/dist/chat/chat.agent.d.ts +0 -6
  6. package/dist/chat/chat.agent.js +0 -94
  7. package/dist/chat/chat.persona.d.ts +1 -2
  8. package/dist/chat/chat.prompt.js +1 -1
  9. package/dist/chat/chat.prompt.modules.d.ts +0 -2
  10. package/dist/index.d.ts +0 -1
  11. package/dist/index.js +0 -1
  12. package/dist/mcp/elicitation.builder.d.ts +1 -1
  13. package/dist/mcp/elicitation.dispatcher.d.ts +1 -1
  14. package/dist/questions/index.d.ts +37 -8
  15. package/dist/questions/index.js +38 -2
  16. package/dist/questions/{application/question.agent.d.ts → question.agent.d.ts} +2 -2
  17. package/dist/questions/{application/question.agent.js → question.agent.js} +6 -9
  18. package/dist/questions/{application/question.ask.tool.d.ts → question.ask.tool.d.ts} +2 -2
  19. package/dist/questions/{application/question.ask.tool.js → question.ask.tool.js} +4 -7
  20. package/dist/questions/{application/question.env.d.ts → question.env.d.ts} +1 -4
  21. package/dist/questions/{application/question.env.js → question.env.js} +1 -4
  22. package/dist/questions/{application/question.input.d.ts → question.input.d.ts} +4 -7
  23. package/dist/questions/{application/question.input.js → question.input.js} +1 -1
  24. package/dist/questions/{ports/question.persistence.port.d.ts → question.persistence.port.d.ts} +2 -4
  25. package/dist/questions/{application/question.presets.d.ts → question.presets.d.ts} +2 -5
  26. package/dist/questions/{application/question.presets.js → question.presets.js} +12 -2
  27. package/dist/questions/{domain/question.schema.d.ts → question.schema.d.ts} +43 -47
  28. package/dist/questions/{domain/question.schema.js → question.schema.js} +32 -32
  29. package/dist/questions/{application/question.tools.d.ts → question.tools.d.ts} +2 -2
  30. package/dist/questions/{application/question.tools.js → question.tools.js} +4 -7
  31. package/dist/questions/{ports/question.tools.port.d.ts → question.tools.port.d.ts} +2 -4
  32. package/dist/shared/agent/tool.factory.js +0 -1
  33. package/dist/shared/agent/tool.helpers.d.ts +3 -11
  34. package/dist/shared/agent/tool.helpers.js +1 -2
  35. package/dist/shared/schemas/pending-question.schema.d.ts +1 -1
  36. package/dist/shared/schemas/underspecification.schema.d.ts +1 -1
  37. package/dist/shared/schemas/underspecification.schema.js +1 -1
  38. package/package.json +1 -1
  39. package/dist/chat/reporter.action.contracts.d.ts +0 -36
  40. package/dist/chat/reporter.action.contracts.js +0 -1
  41. package/dist/chat/reporter.action.tools.d.ts +0 -17
  42. package/dist/chat/reporter.action.tools.js +0 -145
  43. package/dist/chat/reporter.persona.d.ts +0 -31
  44. package/dist/chat/reporter.persona.js +0 -207
  45. package/dist/chat/reporter.prompt.d.ts +0 -24
  46. package/dist/chat/reporter.prompt.js +0 -149
  47. package/dist/questions/application/index.d.ts +0 -39
  48. package/dist/questions/application/index.js +0 -41
  49. package/dist/questions/application/question.qud.d.ts +0 -12
  50. package/dist/questions/application/question.qud.js +0 -16
  51. package/dist/questions/domain/index.d.ts +0 -24
  52. package/dist/questions/domain/index.js +0 -24
  53. package/dist/questions/ports/index.d.ts +0 -27
  54. package/dist/questions/ports/index.js +0 -26
  55. /package/dist/questions/{ports/question.persistence.port.js → question.persistence.port.js} +0 -0
  56. /package/dist/questions/{ports/question.tools.port.js → question.tools.port.js} +0 -0
@@ -1,145 +0,0 @@
1
- import { tool } from "@langchain/core/tools";
2
- import { z } from "zod";
3
- import { success } from "../shared/agent/tool.helpers.js";
4
- export const AGENT_ACTION_PROPOSAL_FENCE = "agent_action_proposal";
5
- const actionInputSchema = z.discriminatedUnion("type", [
6
- z.object({
7
- type: z.literal("retract_premise"),
8
- premiseId: z.string().trim().min(1),
9
- }).strict(),
10
- z.object({
11
- type: z.literal("narrow_signal"),
12
- intentId: z.string().trim().min(1),
13
- description: z.string().trim().min(1),
14
- }).strict(),
15
- z.object({
16
- type: z.literal("pause_signal"),
17
- intentId: z.string().trim().min(1),
18
- evidence: z.string().trim().min(1, "pause_signal evidence is required"),
19
- }).strict(),
20
- ]);
21
- const proposeCleanupActionsSchema = z.object({
22
- actions: z.array(actionInputSchema).min(1).max(5),
23
- }).strict();
24
- function isFullUuid(value) {
25
- return z.string().uuid().safeParse(value).success;
26
- }
27
- function skippedAction(action, entityId, proposedOperation, reason) {
28
- return {
29
- type: action.type,
30
- entityId,
31
- currentState: "UNKNOWN",
32
- proposedOperation,
33
- skipped: true,
34
- reason,
35
- ...(action.type === "pause_signal" ? { evidence: action.evidence } : {}),
36
- };
37
- }
38
- /**
39
- * Creates the reporter-only proposal tool. It validates owner state and records
40
- * snapshots, but intentionally has no mutation dependency.
41
- */
42
- export function createProposeCleanupActionsTool(input) {
43
- const { database, userDb, context, store } = input;
44
- return tool(async (query) => {
45
- const proposalId = crypto.randomUUID();
46
- const actions = [];
47
- for (const action of query.actions) {
48
- const entityId = action.type === "retract_premise" ? action.premiseId : action.intentId;
49
- const operation = action.type === "retract_premise"
50
- ? "RETRACT_PREMISE"
51
- : action.type === "narrow_signal" ? "NARROW_SIGNAL" : "PAUSE_SIGNAL";
52
- if (!isFullUuid(entityId)) {
53
- actions.push(skippedAction(action, entityId, operation, "A full UUID is required; suffixes and ambiguous IDs are not accepted."));
54
- continue;
55
- }
56
- if (action.type === "retract_premise") {
57
- const premise = await database.getPremise(entityId).catch(() => null);
58
- if (!premise || premise.userId !== context.userId) {
59
- actions.push(skippedAction(action, entityId, operation, "Premise not found or not owned by the authenticated user."));
60
- continue;
61
- }
62
- if (premise.status !== "ACTIVE") {
63
- actions.push({
64
- type: action.type,
65
- entityId,
66
- currentState: premise.status,
67
- proposedOperation: operation,
68
- skipped: true,
69
- reason: `Premise is already ${premise.status}.`,
70
- });
71
- continue;
72
- }
73
- actions.push({
74
- type: action.type,
75
- entityId,
76
- currentState: premise.status,
77
- proposedOperation: operation,
78
- snapshot: { status: premise.status, updatedAt: premise.updatedAt.toISOString(), assertionText: premise.assertion.text },
79
- });
80
- continue;
81
- }
82
- const intent = await userDb.getIntent(entityId).catch(() => null);
83
- if (!intent) {
84
- actions.push(skippedAction(action, entityId, operation, "Signal not found or not owned by the authenticated user."));
85
- continue;
86
- }
87
- const status = intent.status ?? "ACTIVE";
88
- if (intent.archivedAt || status === "FULFILLED" || status === "EXPIRED") {
89
- actions.push({
90
- type: action.type,
91
- entityId,
92
- currentState: intent.archivedAt ? "ARCHIVED" : status,
93
- proposedOperation: operation,
94
- ...(action.type === "pause_signal" ? { evidence: action.evidence } : {}),
95
- skipped: true,
96
- reason: "Signal is archived or terminal and cannot be changed.",
97
- });
98
- continue;
99
- }
100
- actions.push({
101
- type: action.type,
102
- entityId,
103
- currentState: status,
104
- proposedOperation: operation,
105
- ...(action.type === "pause_signal" ? { evidence: action.evidence } : {}),
106
- ...(action.type === "narrow_signal" ? { description: action.description } : {}),
107
- snapshot: {
108
- status,
109
- updatedAt: intent.updatedAt.toISOString(),
110
- payload: intent.payload,
111
- summary: intent.summary,
112
- },
113
- });
114
- }
115
- await store.createProposal({
116
- proposalId,
117
- userId: context.userId,
118
- ...(context.sessionId ? { conversationId: context.sessionId } : {}),
119
- actions,
120
- });
121
- const renderedActions = actions.map(({ snapshot: _snapshot, ...entry }) => entry);
122
- const block = `\`\`\`${AGENT_ACTION_PROPOSAL_FENCE}\n${JSON.stringify({ proposalId, actions: renderedActions })}\n\`\`\``;
123
- return success({
124
- proposed: true,
125
- proposalId,
126
- actions: renderedActions,
127
- message: `IMPORTANT: Include this \`\`\`agent_action_proposal code block EXACTLY as-is in your response. It is a REQUEST for owner confirmation; it performs no mutation until the owner confirms it in the UI:\n\n${block}`,
128
- });
129
- }, {
130
- name: "propose_cleanup_actions",
131
- description: "Prepare owner-confirmed cleanup actions from same-turn grounded reads. This tool never mutates data.",
132
- schema: proposeCleanupActionsSchema,
133
- });
134
- }
135
- /** Build the optional action tool from the host-provided ToolContext. */
136
- export function createReporterActionTool(deps, context, userDb) {
137
- if (!deps.actionToolsEnabled || !deps.actionProposalStore)
138
- return null;
139
- return createProposeCleanupActionsTool({
140
- database: deps.database,
141
- userDb,
142
- context,
143
- store: deps.actionProposalStore,
144
- });
145
- }
@@ -1,31 +0,0 @@
1
- import { type ChatTools, type ResolvedToolContext, type ToolContext } from "../shared/agent/tool.factory.js";
2
- import type { UserDatabase } from "../shared/interfaces/database.interface.js";
3
- import type { ChatPersonaConfig } from "./chat.persona.js";
4
- /** Public kickoff marker used by the Agent surface to request its opening briefing. */
5
- export { REPORTER_BRIEFING_KICKOFF } from "./reporter.prompt.js";
6
- /** Stable persona id persisted for read-only Agent reporting sessions. */
7
- export declare const REPORTER_PERSONA_ID = "reporter";
8
- /**
9
- * Exact positive allowlist for the reporter persona. New shared tools remain
10
- * unavailable until they are explicitly reviewed here.
11
- */
12
- export declare const REPORTER_TOOL_NAMES: readonly ["read_intents", "search_intents", "read_user_contexts", "preview_user_context", "read_premises", "read_networks", "read_network_memberships", "read_pending_questions", "list_opportunities", "read_activity_summary"];
13
- interface ReporterToolBoundary {
14
- context: ResolvedToolContext;
15
- userDb: UserDatabase;
16
- findPendingQuestions?: ToolContext["findPendingQuestions"];
17
- }
18
- /** Filters a shared registry through the reporter's positive allowlist. */
19
- export declare function filterReporterTools<T extends {
20
- name: string;
21
- }>(tools: T[]): T[];
22
- /**
23
- * Replaces shared tools whose normal modes can enumerate other users with
24
- * reporter-safe, self-only read contracts. Opportunity listing is deliberately
25
- * aggregate-only: it never returns a counterpart name, row, or explanation.
26
- */
27
- export declare function narrowReporterTools(allowed: ChatTools, boundary: ReporterToolBoundary): ChatTools;
28
- /** Creates the reporter's context-bound, allowlisted toolset. */
29
- export declare function createReporterTools(deps: ToolContext, preResolvedContext?: ResolvedToolContext): Promise<ChatTools>;
30
- /** Restricted read-only Agent reporter persona. */
31
- export declare const REPORTER_PERSONA: ChatPersonaConfig;
@@ -1,207 +0,0 @@
1
- import { tool } from "@langchain/core/tools";
2
- import { z } from "zod";
3
- import { createChatTools } from "../shared/agent/tool.factory.js";
4
- import { error, resolveChatContext, success } from "../shared/agent/tool.helpers.js";
5
- import { focusedNetworkId, scopeFromNetworkId } from "../shared/agent/tool.scope.js";
6
- import { buildReporterSystemContent, resolveReporterDeterministicResponse } from "./reporter.prompt.js";
7
- import { createReporterActionTool } from "./reporter.action.tools.js";
8
- /** Public kickoff marker used by the Agent surface to request its opening briefing. */
9
- export { REPORTER_BRIEFING_KICKOFF } from "./reporter.prompt.js";
10
- /** Stable persona id persisted for read-only Agent reporting sessions. */
11
- export const REPORTER_PERSONA_ID = "reporter";
12
- /**
13
- * Exact positive allowlist for the reporter persona. New shared tools remain
14
- * unavailable until they are explicitly reviewed here.
15
- */
16
- export const REPORTER_TOOL_NAMES = [
17
- "read_intents",
18
- "search_intents",
19
- "read_user_contexts",
20
- "preview_user_context",
21
- "read_premises",
22
- "read_networks",
23
- "read_network_memberships",
24
- "read_pending_questions",
25
- "list_opportunities",
26
- "read_activity_summary",
27
- ];
28
- const REPORTER_TOOL_ALLOWLIST = new Set(REPORTER_TOOL_NAMES);
29
- /** Filters a shared registry through the reporter's positive allowlist. */
30
- export function filterReporterTools(tools) {
31
- return tools.filter((candidate) => REPORTER_TOOL_ALLOWLIST.has(candidate.name));
32
- }
33
- function invokeSharedTool(sharedTool, input) {
34
- return sharedTool.invoke(input);
35
- }
36
- /**
37
- * Replaces shared tools whose normal modes can enumerate other users with
38
- * reporter-safe, self-only read contracts. Opportunity listing is deliberately
39
- * aggregate-only: it never returns a counterpart name, row, or explanation.
40
- */
41
- export function narrowReporterTools(allowed, boundary) {
42
- const { context, userDb } = boundary;
43
- return allowed.map((sharedTool) => {
44
- if (sharedTool.name === "read_intents") {
45
- return tool(async (query) => {
46
- const limit = query.limit ?? 100;
47
- const page = query.page ?? 1;
48
- const intents = await userDb.getActiveIntents();
49
- const start = (page - 1) * limit;
50
- return success({
51
- intents: intents.slice(start, start + limit),
52
- page,
53
- limit,
54
- total: intents.length,
55
- });
56
- }, {
57
- name: "read_intents",
58
- description: "Read the authenticated user's own active signals only.",
59
- schema: z.object({
60
- limit: z.number().int().min(1).max(100).optional(),
61
- page: z.number().int().min(1).optional(),
62
- }).strict(),
63
- });
64
- }
65
- if (sharedTool.name === "search_intents") {
66
- return tool(async (query) => success({
67
- intents: await userDb.searchOwnIntents(query.query, query.limit ?? 20),
68
- }), {
69
- name: "search_intents",
70
- description: "Search the authenticated user's own active signals only.",
71
- schema: z.object({
72
- query: z.string().trim().min(1),
73
- limit: z.number().int().min(1).max(100).optional(),
74
- }).strict(),
75
- });
76
- }
77
- if (sharedTool.name === "read_user_contexts") {
78
- return tool(async () => invokeSharedTool(sharedTool, {}), {
79
- name: "read_user_contexts",
80
- description: "Read the authenticated user's own identity and global context only.",
81
- schema: z.object({}).strict(),
82
- });
83
- }
84
- if (sharedTool.name === "read_premises") {
85
- return tool(async (query) => invokeSharedTool(sharedTool, {
86
- includeRetracted: query.includeRetracted ?? false,
87
- userId: context.userId,
88
- }), {
89
- name: "read_premises",
90
- description: "Read the authenticated user's own premises only.",
91
- schema: z.object({ includeRetracted: z.boolean().optional() }).strict(),
92
- });
93
- }
94
- if (sharedTool.name === "read_network_memberships") {
95
- return tool(async () => invokeSharedTool(sharedTool, {}), {
96
- name: "read_network_memberships",
97
- description: "Read the authenticated user's own network memberships only.",
98
- schema: z.object({}).strict(),
99
- });
100
- }
101
- if (sharedTool.name === "read_networks") {
102
- return tool(async () => invokeSharedTool(sharedTool, { userId: context.userId }), {
103
- name: "read_networks",
104
- description: "Read networks available to the authenticated user.",
105
- schema: z.object({}).strict(),
106
- });
107
- }
108
- if (sharedTool.name === "read_pending_questions") {
109
- return tool(async (query) => {
110
- if (!boundary.findPendingQuestions)
111
- return error("Question lookup is not available.");
112
- const questions = await boundary.findPendingQuestions(context.userId, {
113
- modes: ["intent"],
114
- limit: query.limit ?? 10,
115
- });
116
- return success({ questions: questions.slice(0, query.limit ?? 10) });
117
- }, {
118
- name: "read_pending_questions",
119
- description: "Read the user's own non-negotiation pending questions; answering is unavailable here.",
120
- schema: z.object({ limit: z.number().int().min(1).max(10).optional() }).strict(),
121
- });
122
- }
123
- if (sharedTool.name === "list_opportunities") {
124
- return tool(async (query) => {
125
- const scopedNetworkId = focusedNetworkId(context);
126
- if (scopedNetworkId && query.networkId && query.networkId !== scopedNetworkId) {
127
- return error("This chat is scoped to a different network.");
128
- }
129
- const activeIntents = await userDb.getActiveIntents();
130
- const intentById = new Map(activeIntents.map((intent) => [intent.id, intent]));
131
- const opportunities = await userDb.getOpportunitiesForUser({
132
- ...(query.networkId || scopedNetworkId ? { networkId: query.networkId || scopedNetworkId } : {}),
133
- statuses: ["draft", "pending", "latent"],
134
- limit: 100,
135
- });
136
- const counts = new Map();
137
- const seen = new Set();
138
- for (const opportunity of opportunities) {
139
- const ownIntentIds = new Set(opportunity.actors
140
- .filter((actor) => actor.userId === context.userId && actor.intent && intentById.has(actor.intent))
141
- .map((actor) => actor.intent));
142
- if (ownIntentIds.size === 0)
143
- continue;
144
- seen.add(opportunity.id);
145
- for (const intentId of ownIntentIds) {
146
- const intent = intentById.get(intentId);
147
- if (!intent)
148
- continue;
149
- const existing = counts.get(intentId) ?? {
150
- intentId,
151
- title: intent.summary?.trim() || intent.payload,
152
- count: 0,
153
- };
154
- existing.count += 1;
155
- counts.set(intentId, existing);
156
- }
157
- }
158
- return success({
159
- found: seen.size > 0,
160
- count: seen.size,
161
- bySignal: [...counts.values()],
162
- });
163
- }, {
164
- name: "list_opportunities",
165
- description: "Report current opportunity counts by the user's own signal, without counterpart identities or rows.",
166
- schema: z.object({ networkId: z.string().uuid().optional() }).strict(),
167
- });
168
- }
169
- return sharedTool;
170
- });
171
- }
172
- /** Creates the reporter's context-bound, allowlisted toolset. */
173
- export async function createReporterTools(deps, preResolvedContext) {
174
- const explicitScope = deps.scopeType && deps.scopeId
175
- ? { scopeType: deps.scopeType, scopeId: deps.scopeId }
176
- : scopeFromNetworkId(deps.networkId);
177
- const resolvedContext = preResolvedContext ?? await resolveChatContext({
178
- database: deps.database,
179
- userId: deps.userId,
180
- networkId: explicitScope.scopeType === "network" ? explicitScope.scopeId : deps.networkId,
181
- sessionId: deps.sessionId,
182
- actionToolsEnabled: deps.actionToolsEnabled,
183
- });
184
- if (explicitScope.scopeType && explicitScope.scopeId) {
185
- resolvedContext.scopeType = explicitScope.scopeType;
186
- resolvedContext.scopeId = explicitScope.scopeId;
187
- }
188
- const userDb = deps.userDb ?? deps.createUserDatabase(deps.database, resolvedContext.userId);
189
- const allowed = filterReporterTools(await createChatTools(deps, resolvedContext));
190
- const narrowed = narrowReporterTools(allowed, {
191
- context: resolvedContext,
192
- userDb,
193
- findPendingQuestions: deps.findPendingQuestions,
194
- });
195
- const actionTool = createReporterActionTool(deps, resolvedContext, userDb);
196
- return actionTool ? [...narrowed, actionTool] : narrowed;
197
- }
198
- /** Restricted read-only Agent reporter persona. */
199
- export const REPORTER_PERSONA = {
200
- id: REPORTER_PERSONA_ID,
201
- buildSystemContent: (ctx, iterCtx) => buildReporterSystemContent(ctx, iterCtx),
202
- createTools: (deps, preResolvedContext) => createReporterTools(deps, preResolvedContext),
203
- resolveDeterministicResponse: (_ctx, iterCtx) => resolveReporterDeterministicResponse(iterCtx),
204
- loopBehaviors: {
205
- hallucinationRecovery: false,
206
- },
207
- };
@@ -1,24 +0,0 @@
1
- import type { ResolvedToolContext } from "../shared/agent/tool.factory.js";
2
- import type { IterationContext } from "./chat.prompt.modules.js";
3
- /** Stable marker used by the Agent surface to request its opening briefing. */
4
- export declare const REPORTER_BRIEFING_KICKOFF = "reporter-briefing-kickoff";
5
- /**
6
- * Recognizes the explicit opening briefing marker without putting ordinary
7
- * reporter conversations into briefing mode accidentally.
8
- *
9
- * @param message - Latest user message in the current turn
10
- * @returns Whether this turn is the Agent-surface briefing kickoff
11
- */
12
- export declare function isReporterBriefingKickoff(message?: string): boolean;
13
- /** Recognizes a short acknowledgement only when a prior proposal is visible. */
14
- export declare function isReporterActionConfirmation(message?: string, hasPriorProposal?: boolean): boolean;
15
- /** Deterministic reporter response for contextual typed acknowledgements. */
16
- export declare function resolveReporterDeterministicResponse(iterCtx: IterationContext): string | null;
17
- /**
18
- * Builds the read-only reporter persona prompt.
19
- *
20
- * @param ctx - Resolved authenticated user context
21
- * @param iterCtx - Current agent-loop context used for briefing kickoff
22
- * @returns Complete reporter system content
23
- */
24
- export declare function buildReporterSystemContent(ctx: ResolvedToolContext, iterCtx?: IterationContext): string;
@@ -1,149 +0,0 @@
1
- /** Stable marker used by the Agent surface to request its opening briefing. */
2
- export const REPORTER_BRIEFING_KICKOFF = "reporter-briefing-kickoff";
3
- /**
4
- * Recognizes the explicit opening briefing marker without putting ordinary
5
- * reporter conversations into briefing mode accidentally.
6
- *
7
- * @param message - Latest user message in the current turn
8
- * @returns Whether this turn is the Agent-surface briefing kickoff
9
- */
10
- export function isReporterBriefingKickoff(message) {
11
- const normalized = message?.trim().toLocaleLowerCase()
12
- .replace(/[–—]/g, "-")
13
- .replace(/^_+|_+$/g, "");
14
- if (!normalized)
15
- return false;
16
- return normalized === REPORTER_BRIEFING_KICKOFF;
17
- }
18
- /** Recognizes a short acknowledgement only when a prior proposal is visible. */
19
- export function isReporterActionConfirmation(message, hasPriorProposal = false) {
20
- const normalized = message?.trim().toLocaleLowerCase()
21
- .replace(/[.!?,;:]+$/g, "")
22
- .replace(/\s+/g, " ");
23
- if (!normalized || !hasPriorProposal)
24
- return false;
25
- return new Set([
26
- "i confirm",
27
- "confirm",
28
- "confirm it",
29
- "approve",
30
- "approved",
31
- "approve it",
32
- "i approve",
33
- "yes",
34
- "yes i confirm",
35
- "yes please",
36
- "please do it",
37
- "proceed",
38
- "go ahead",
39
- ]).has(normalized);
40
- }
41
- /** Deterministic reporter response for contextual typed acknowledgements. */
42
- export function resolveReporterDeterministicResponse(iterCtx) {
43
- if (!isReporterActionConfirmation(iterCtx.currentMessage, iterCtx.hasPriorAgentActionProposal === true))
44
- return null;
45
- return "Use the visible proposal card's Confirm control to approve this request. I won't run or recreate it from a chat acknowledgement.";
46
- }
47
- function buildBriefingGuidance(iterCtx) {
48
- if (!isReporterBriefingKickoff(iterCtx?.currentMessage))
49
- return "";
50
- return `
51
-
52
- ## Opening briefing
53
- This is the Agent-surface briefing kickoff. Call read_activity_summary first with the default window, then call the read tools needed to ground the four transparency asks below. Present one concise briefing covering:
54
- 1. summarize all my signals;
55
- 2. what did you do today?;
56
- 3. how do I look to others?;
57
- 4. what should I sharpen?
58
- Do not claim a metric unless it appears in a tool result from this turn. If a section has no grounded data, say that plainly rather than filling the gap.`;
59
- }
60
- function buildTurnGuidance(iterCtx) {
61
- const currentMessage = iterCtx?.currentMessage;
62
- const confirmation = isReporterActionConfirmation(currentMessage, iterCtx?.hasPriorAgentActionProposal === true);
63
- return `
64
-
65
- ## Turn discipline
66
- - The detailed four-section opening briefing is reserved for the exact reporter-briefing-kickoff marker. Do not repeat the full briefing or duplicate all reads for a focused follow-up.
67
- - For every non-kickoff message, answer only the user's current request and perform only the reads needed to answer it.
68
- ${confirmation ? `- This message is only a natural-language acknowledgement. Never execute, claim execution, create, or reuse an action proposal in response. Do not call read_activity_summary or propose_cleanup_actions. Tell the owner to use the visible proposal card's Confirm control; “${currentMessage?.trim()}” is not endpoint confirmation.` : ""}`;
69
- }
70
- /**
71
- * Builds the read-only reporter persona prompt.
72
- *
73
- * @param ctx - Resolved authenticated user context
74
- * @param iterCtx - Current agent-loop context used for briefing kickoff
75
- * @returns Complete reporter system content
76
- */
77
- export function buildReporterSystemContent(ctx, iterCtx) {
78
- const userContext = JSON.stringify(ctx.user, null, 2);
79
- const profileContext = ctx.userProfile
80
- ? JSON.stringify(ctx.userProfile, null, 2)
81
- : "null";
82
- const membershipContext = JSON.stringify(ctx.userNetworks.map((network) => ({
83
- id: network.networkId,
84
- title: network.networkTitle,
85
- isPersonal: network.isPersonal,
86
- })), null, 2);
87
- const roleGuidance = ctx.actionToolsEnabled
88
- ? "Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You may prepare a cleanup-action request from grounded same-turn reads, but you never change anything in chat."
89
- : "Your role is to report what the user's Index agent has done and what the user's own signals currently communicate. You observe; you never change anything. Suggestions such as pausing or merging a signal are recommendations for the user to carry out through existing product UI, never actions for this persona.";
90
- const mutationRule = ctx.actionToolsEnabled
91
- ? "- Never mutate data in chat. You may call propose_cleanup_actions only after same-turn owner-scoped reads; it creates a REQUEST block and never executes an action. The owner must confirm through the product UI."
92
- : "- Never create, update, delete, confirm, answer, remember, forget, assign, discover, negotiate, scrape, or otherwise mutate data. Do not ask the user a question through a tool.";
93
- const actionGuidance = ctx.actionToolsEnabled ? `
94
-
95
- ## Cleanup-action requests
96
- - You may propose only retract_premise, narrow_signal, and pause_signal actions grounded in read results from this same turn.
97
- - Resolve references through owner-scoped read tools and pass exact full UUIDs only; never use suffixes, guesses, or IDs from another user.
98
- - pause_signal requires non-empty evidence recorded from this turn, such as zero live opportunities plus the owner's statement.
99
- - The proposal block is a REQUEST for owner confirmation. Never narrate an action as completed and never mutate inside chat.
100
- - Do not propose actions for counterparties or expose counterparty identity.
101
- ` : "";
102
- return `You are Agent, the user's private read-only activity reporter for ${ctx.userName}.
103
-
104
- ${roleGuidance}${actionGuidance}
105
-
106
- ## Hard rules
107
- - Every factual claim, number, status, or trend must come from a tool result in the current turn. Never invent, estimate, or reuse an unverified metric.
108
- - Use read_activity_summary for activity counts and read_intents/read_user_contexts/read_premises/read_networks/read_network_memberships/read_pending_questions for the underlying current state.
109
- - Counterparties are identity-free aggregate data only: never reveal names, IDs, transcripts, message text, or per-counterparty rows. Do not infer what another person thinks from a match or negotiation.
110
- ${mutationRule}
111
- - Do not write observed behavior back as a preference or premise. The user decides whether to act on a suggestion.
112
- - If opportunity information is relevant, use only the restricted list_opportunities result or read_activity_summary result. Do not expose raw evaluator reasoning, matchReason, or internal JSON. Any opportunity copy must be presenter-backed; this persona's list view is aggregate-only.
113
- - Be transparent about missing data and the reporting window. Keep the response concise, calm, and useful without hype.
114
-
115
- ## Four transparency asks
116
- Be ready to answer:
117
- - “summarize all my signals” — read the user's own signals and describe their current themes without inventing a synthesis.
118
- - “what did you do today?” — report only grounded activity counts from the requested window.
119
- - “how do I look to others?” — describe only the user's own stored context and signals; do not claim access to private counterparty opinions.
120
- - “what should I sharpen?” — suggest possible signal/context improvements based on observed gaps in the returned data, clearly label them as suggestions, and point the user to existing UI. Never apply them.
121
-
122
- ## Allowed capabilities
123
- - Own signal reads: read_intents, search_intents.
124
- - Own context reads: read_user_contexts, preview_user_context, read_premises.
125
- - Own community context: read_networks, read_network_memberships.
126
- - Own pending-question reads: read_pending_questions (never answer them).
127
- - Aggregate activity reporting: read_activity_summary.
128
- - Aggregate current opportunity reporting: list_opportunities (no counterpart identities or rows).${ctx.actionToolsEnabled ? "\n- Cleanup-action requests: propose_cleanup_actions (request only; owner confirmation is required)." : ""}
129
-
130
- ## Session identity (preloaded)
131
- - User: ${ctx.userName} (${ctx.userEmail}), id: ${ctx.userId}
132
-
133
- ### User record
134
- \`\`\`json
135
- ${userContext}
136
- \`\`\`
137
-
138
- ### User context
139
- \`\`\`json
140
- ${profileContext}
141
- \`\`\`
142
-
143
- ### Current memberships
144
- \`\`\`json
145
- ${membershipContext}
146
- \`\`\`
147
-
148
- Only the identity, context, and membership metadata above are preloaded. Signals, premises, questions, and activity are not preloaded: call the appropriate read/report tool before describing them.${buildTurnGuidance(iterCtx)}${buildBriefingGuidance(iterCtx)}`;
149
- }
@@ -1,39 +0,0 @@
1
- /**
2
- * questions/application — orchestrators, agents, env, tools, and presets.
3
- *
4
- * Re-exports the orchestration tier of the questions capability: the
5
- * QuestionerAgent, env accessors, generation presets, and adapter tool
6
- * factories.
7
- *
8
- * ## Foreground adapters (participant-directed, authenticated)
9
- *
10
- * - {@link createQuestionerTools} — `read_pending_questions` and
11
- * `answer_pending_question` MCP tools for authenticated answer/dismiss paths.
12
- * - {@link createAskUserQuestionTools} — blocking chat `ask_user_question`
13
- * tool for inline chat orchestrator questions.
14
- *
15
- * ## Ambient adapters (background generation)
16
- *
17
- * Recovery, pool, uptake, inflight, and push generation are scheduled via
18
- * the QuestionerQueue (backend). They consume {@link QuestionerEnqueueFn}
19
- * injected from the composition root and call QuestionerAgent.invoke() with
20
- * the appropriate mode context. The ports for these adapters are declared in
21
- * `questions/ports/question.persistence.port.ts`.
22
- *
23
- * ## Boundary
24
- *
25
- * Imports from questions/domain, questions/ports, shared/ infrastructure,
26
- * and narrow capability facades (negotiation.questions.facade) — never from
27
- * runtime/, host implementations, or other capability internals.
28
- *
29
- * IND-547: canonical application layer for the questions capability.
30
- */
31
- export { isValidQuestionerInputContract, } from "./question.input.js";
32
- export type { QuestionerInput, QuestionerContext, QuestionerEnqueuePayload, QuestionerEnqueueFn, IntentContext, RecoveryIntentContext, NegotiationContext, PostStallNegotiationContext, UptakeNegotiationContext, NegotiationInflightContext, ChatContext, PoolDiscoveryContext, PostStallQuestionerInput, InflightQuestionerInput, UptakeQuestionerInput, RecoveryQuestionerInput, } from "./question.input.js";
33
- export { QuestionerAgent } from "./question.agent.js";
34
- export type { QuestionerAgentConfig } from "./question.agent.js";
35
- export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
36
- export { getPreset } from "./question.presets.js";
37
- export type { QuestionerPreset } from "./question.presets.js";
38
- export { createQuestionerTools } from "./question.tools.js";
39
- export { createAskUserQuestionTools, setQuestionerAgentForTesting } from "./question.ask.tool.js";
@@ -1,41 +0,0 @@
1
- /**
2
- * questions/application — orchestrators, agents, env, tools, and presets.
3
- *
4
- * Re-exports the orchestration tier of the questions capability: the
5
- * QuestionerAgent, env accessors, generation presets, and adapter tool
6
- * factories.
7
- *
8
- * ## Foreground adapters (participant-directed, authenticated)
9
- *
10
- * - {@link createQuestionerTools} — `read_pending_questions` and
11
- * `answer_pending_question` MCP tools for authenticated answer/dismiss paths.
12
- * - {@link createAskUserQuestionTools} — blocking chat `ask_user_question`
13
- * tool for inline chat orchestrator questions.
14
- *
15
- * ## Ambient adapters (background generation)
16
- *
17
- * Recovery, pool, uptake, inflight, and push generation are scheduled via
18
- * the QuestionerQueue (backend). They consume {@link QuestionerEnqueueFn}
19
- * injected from the composition root and call QuestionerAgent.invoke() with
20
- * the appropriate mode context. The ports for these adapters are declared in
21
- * `questions/ports/question.persistence.port.ts`.
22
- *
23
- * ## Boundary
24
- *
25
- * Imports from questions/domain, questions/ports, shared/ infrastructure,
26
- * and narrow capability facades (negotiation.questions.facade) — never from
27
- * runtime/, host implementations, or other capability internals.
28
- *
29
- * IND-547: canonical application layer for the questions capability.
30
- */
31
- // ── Domain input types + validation ──────────────────────────────────────────
32
- export { isValidQuestionerInputContract, } from "./question.input.js";
33
- // ── Agent ─────────────────────────────────────────────────────────────────────
34
- export { QuestionerAgent } from "./question.agent.js";
35
- // ── Env ───────────────────────────────────────────────────────────────────────
36
- export { isQuestionerEnabled, isUptakeGuardEnabled, uptakeAuthorityThreshold, chatQuestionWaitTimeoutMs, intentQuestionDailyCap, CHAT_QUESTION_WAIT_TIMEOUT_MS_DEFAULT, UPTAKE_AUTHORITY_THRESHOLD_DEFAULT, INTENT_QUESTION_DAILY_CAP_DEFAULT, INTENT_QUESTION_DAILY_WINDOW_HOURS, } from "./question.env.js";
37
- // ── Presets ───────────────────────────────────────────────────────────────────
38
- export { getPreset } from "./question.presets.js";
39
- // ── Foreground adapter tools ──────────────────────────────────────────────────
40
- export { createQuestionerTools } from "./question.tools.js";
41
- export { createAskUserQuestionTools, setQuestionerAgentForTesting } from "./question.ask.tool.js";
@@ -1,12 +0,0 @@
1
- /**
2
- * questions/application/question.qud — Questions Under Discussion taxonomy.
3
- *
4
- * Shared QUD taxonomy contract for structured question-generation prompts.
5
- * Every Questioner mode uses this block because the structured output schema
6
- * requires the internal metadata field; intent and discovery are the primary
7
- * consumers of non-null classifications.
8
- *
9
- * IND-547: canonical home — previously questioner/questioner.qud.ts.
10
- * Legacy path is a thin compatibility shim pointing here.
11
- */
12
- export declare const QUD_UNDERSPECIFICATION_RULES = "QUD underspecification taxonomy. For every structured question, emit a required `underspecificationType` field. Use exactly one category only when the question repairs that kind of underspecification:\n- missing_constituent: an absent core participant, entity, or outcome (who/what).\n- missing_constraint: the core target exists, but a ranking boundary is missing (where/when/how/how much).\n- open_alternative_set: an unresolved choice among materially different interpretations or scopes.\nUse null for adjacent, reflective, emergent, or any other question that does not repair underspecification. Strategy and underspecification type are orthogonal: `strategy` describes the conversational move; `underspecificationType` describes the QUD defect repaired. Never infer one mechanically from the other.";