@tangle-network/agent-app 0.47.4 → 0.47.5

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.
@@ -0,0 +1,230 @@
1
+ import {
2
+ createChatTurnRoutes,
3
+ streamChatRouteAsSandboxEvents
4
+ } from "../chunk-LYAYNWDS.js";
5
+ import "../chunk-ZSSCVT6H.js";
6
+ import "../chunk-F7VH4G5C.js";
7
+ import "../chunk-IRYULX3R.js";
8
+ import "../chunk-ZVEEWGDK.js";
9
+ import "../chunk-DXHUQ5NO.js";
10
+ import "../chunk-JEZJ6HTF.js";
11
+ import "../chunk-ZMMIQOFI.js";
12
+ import "../chunk-M3K2HVQD.js";
13
+ import "../chunk-YJMCRXQQ.js";
14
+ import "../chunk-ES3I3UGP.js";
15
+
16
+ // src/public-consultation/index.ts
17
+ import { searchKnowledge } from "@tangle-network/agent-knowledge";
18
+ function createKnowledgePublication(input) {
19
+ for (const value of [input.id, input.revision, input.ownerId]) requireIdentity(value);
20
+ const pages = [];
21
+ for (const id of new Set(input.pageIds)) {
22
+ const matches = input.index.pages.filter((page2) => page2.id === id);
23
+ if (matches.length !== 1) throw new Error("Publication page must resolve exactly once");
24
+ const page = matches[0];
25
+ pages.push({
26
+ id: page.id,
27
+ title: page.title,
28
+ text: page.text,
29
+ path: page.id,
30
+ frontmatter: {},
31
+ sourceIds: [],
32
+ tags: [],
33
+ outLinks: []
34
+ });
35
+ }
36
+ const index = { root: "", generatedAt: "", sources: [], pages, graph: { nodes: [], edges: [] } };
37
+ const publicPage = (page) => Object.freeze({ id: page.id, title: page.title, text: page.text });
38
+ return Object.freeze({
39
+ id: input.id,
40
+ revision: input.revision,
41
+ ownerId: input.ownerId,
42
+ systemPrompt: input.systemPrompt,
43
+ read: (id) => {
44
+ const page = pages.find((candidate) => candidate.id === id);
45
+ return page ? publicPage(page) : null;
46
+ },
47
+ search: (query) => searchKnowledge(index, query, { limit: 10 }).map((hit) => publicPage(hit.page))
48
+ });
49
+ }
50
+ function createPublicConsultation(options) {
51
+ if (typeof options.turnLock?.acquire !== "function" || typeof options.turnLock.release !== "function") {
52
+ throw new Error("Public consultation requires a shared turn lock");
53
+ }
54
+ async function ownsConversation(identity) {
55
+ const conversation = await options.ensureConversation(identity);
56
+ return conversation?.workspaceId === identity.workspaceId && conversation.threadId === identity.threadId;
57
+ }
58
+ async function resolve(agent, consumer) {
59
+ requireIdentity(consumer.consumerId);
60
+ requireIdentity(consumer.method);
61
+ requireIdentity(consumer.threadId);
62
+ const publication = await options.resolvePublication(agent.id);
63
+ if (!publication || publication.id !== agent.id || publication.ownerId !== agent.ownerId || await options.allowConsumer(publication, consumer) !== true) return null;
64
+ const workspaceId = await scopedId([publication.ownerId, publication.id, publication.revision, consumer.method, consumer.consumerId]);
65
+ const threadId = await scopedId([workspaceId, consumer.threadId]);
66
+ const identity = Object.freeze({
67
+ publicationId: publication.id,
68
+ publicationRevision: publication.revision,
69
+ consumerId: consumer.consumerId,
70
+ paymentMethod: consumer.method,
71
+ workspaceId,
72
+ threadId
73
+ });
74
+ return { publication, identity };
75
+ }
76
+ return {
77
+ async authorizeConsumer(agent, consumer) {
78
+ const scope = await resolve(agent, consumer);
79
+ return scope ? { allow: true } : { allow: false, reason: "Consultation access denied", code: "consultation_forbidden" };
80
+ },
81
+ async readKnowledge(agent, consumer, pageId) {
82
+ const scope = await resolve(agent, consumer);
83
+ if (!scope) throw new Error("Consultation access denied");
84
+ return scope.publication.read(pageId);
85
+ },
86
+ async readHistory(agent, consumer) {
87
+ const scope = await resolve(agent, consumer);
88
+ if (!scope) throw new Error("Consultation access denied");
89
+ if (!await ownsConversation(scope.identity)) throw new Error("Consultation conversation conflict");
90
+ return (await options.store.listMessages(scope.identity.threadId)).map(({ role, content }) => ({ role, content }));
91
+ },
92
+ async getSandbox(agent, context) {
93
+ if (!context) throw new Error("Authenticated consultation identity is required");
94
+ const consumer = {
95
+ consumerId: context.consumerId,
96
+ method: context.paymentMethod,
97
+ requestId: context.requestId,
98
+ threadId: context.threadId,
99
+ keyId: context.keyInfo?.keyId,
100
+ ownerId: context.keyInfo?.ownerId
101
+ };
102
+ const scope = await resolve(agent, consumer);
103
+ if (!scope) throw new Error("Consultation access denied");
104
+ const prompt = context.messages.filter((message) => message.role === "user").at(-1)?.content;
105
+ if (!prompt) throw new Error("Consultation requires a user message");
106
+ const prepare = async (streamOptions) => {
107
+ const signal = streamOptions?.signal ?? new AbortController().signal;
108
+ signal.throwIfAborted();
109
+ const supplied = streamOptions?.executionBudget;
110
+ const executionLimits = supplied || streamOptions?.maxOutputTokens !== void 0 ? Object.freeze({ ...supplied, ...streamOptions?.maxOutputTokens !== void 0 ? { maxOutputTokens: Math.min(streamOptions.maxOutputTokens, supplied?.maxOutputTokens ?? Infinity) } : {} }) : void 0;
111
+ if (executionLimits && Object.values(executionLimits).some((value) => typeof value !== "number" || !Number.isFinite(value) || value < 0)) {
112
+ return { status: "unsupported", reason: "Invalid consultation execution limits" };
113
+ }
114
+ const control = Object.freeze({ identity: scope.identity, signal, executionLimits });
115
+ const prepared = await options.prepareExecution(control);
116
+ signal.throwIfAborted();
117
+ if (prepared?.status !== "prepared" || typeof prepared.produce !== "function") {
118
+ return { status: "unsupported", reason: prepared?.status === "unsupported" ? prepared.reason : "Invalid consultation execution preparation" };
119
+ }
120
+ let started = false;
121
+ const start = () => {
122
+ signal.throwIfAborted();
123
+ if (started) throw new Error("Consultation execution already started");
124
+ started = true;
125
+ const routes = createChatTurnRoutes({
126
+ projectId: "public-consultation",
127
+ store: options.store,
128
+ turnStore: options.turnStore,
129
+ turnLock: options.turnLock,
130
+ authorize: async ({ intent, body }) => {
131
+ const current = await resolve(agent, consumer);
132
+ if (intent !== "turn" || !current || current.identity.workspaceId !== scope.identity.workspaceId || body?.workspaceId !== scope.identity.workspaceId || body.threadId !== scope.identity.threadId) {
133
+ return { ok: false, response: Response.json({ error: "Consultation access denied" }, { status: 403 }) };
134
+ }
135
+ if (!await ownsConversation(scope.identity)) {
136
+ return { ok: false, response: Response.json({ error: "Consultation conversation conflict" }, { status: 403 }) };
137
+ }
138
+ return {
139
+ ok: true,
140
+ tenantId: scope.identity.workspaceId,
141
+ userId: scope.identity.consumerId,
142
+ context: void 0
143
+ };
144
+ },
145
+ produce: (args) => {
146
+ signal.throwIfAborted();
147
+ return prepared.produce({
148
+ ...control,
149
+ identity: scope.identity,
150
+ systemPrompt: scope.publication.systemPrompt,
151
+ prompt,
152
+ priorMessages: args.priorMessages.map(({ role, content }) => ({ role, content })),
153
+ tools: publicationTools(scope.publication, async () => {
154
+ signal.throwIfAborted();
155
+ const current = await resolve(agent, consumer);
156
+ signal.throwIfAborted();
157
+ if (!current || current.identity.workspaceId !== scope.identity.workspaceId) {
158
+ throw new Error("Consultation access denied");
159
+ }
160
+ })
161
+ });
162
+ }
163
+ });
164
+ return streamChatRouteAsSandboxEvents({
165
+ routes,
166
+ request: new Request("https://consultation.invalid/internal"),
167
+ payload: {
168
+ workspaceId: scope.identity.workspaceId,
169
+ threadId: scope.identity.threadId,
170
+ content: prompt,
171
+ turnId: consumer.requestId
172
+ },
173
+ signal,
174
+ executionLimits
175
+ });
176
+ };
177
+ return { status: "prepared", start };
178
+ };
179
+ return {
180
+ prepareBudgetedPrompt: (_message, streamOptions) => prepare(streamOptions),
181
+ streamPrompt: async function* (_message, streamOptions) {
182
+ const prepared = await prepare(streamOptions);
183
+ if (prepared.status !== "prepared") throw new Error(prepared.reason);
184
+ yield* prepared.start();
185
+ }
186
+ };
187
+ }
188
+ };
189
+ }
190
+ function publicationTools(publication, authorize) {
191
+ return [
192
+ {
193
+ name: "knowledge_search",
194
+ description: "Search published consultation knowledge.",
195
+ inputSchema: { type: "object", required: ["query"], properties: { query: { type: "string" } }, additionalProperties: false },
196
+ run: async (args) => {
197
+ await authorize();
198
+ return publication.search(singleArgument(args, "query"));
199
+ }
200
+ },
201
+ {
202
+ name: "knowledge_read",
203
+ description: "Read a published page by its exact citation id.",
204
+ inputSchema: { type: "object", required: ["pageId"], properties: { pageId: { type: "string" } }, additionalProperties: false },
205
+ run: async (args) => {
206
+ await authorize();
207
+ return publication.read(singleArgument(args, "pageId"));
208
+ }
209
+ }
210
+ ];
211
+ }
212
+ function singleArgument(args, name) {
213
+ const value = args[name];
214
+ if (Object.keys(args).length !== 1 || typeof value !== "string" || !value.trim() || value.length > 8192) {
215
+ throw new Error("Invalid published knowledge arguments");
216
+ }
217
+ return value;
218
+ }
219
+ function requireIdentity(value) {
220
+ if (typeof value !== "string" || !value.trim() || value.length > 512) throw new Error("Invalid consultation identity");
221
+ }
222
+ async function scopedId(parts) {
223
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(JSON.stringify(parts)));
224
+ return `consultation:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
225
+ }
226
+ export {
227
+ createKnowledgePublication,
228
+ createPublicConsultation
229
+ };
230
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/public-consultation/index.ts"],"sourcesContent":["import { searchKnowledge, type KnowledgeIndex, type KnowledgePage } from '@tangle-network/agent-knowledge'\nimport { createChatTurnRoutes, type ChatTurnExecutionLimits, type ChatTurnLock, type ChatTurnMessageStore, type ChatTurnRouteProducer } from '../chat-routes/turn-routes'\nimport { streamChatRouteAsSandboxEvents } from '../chat-routes/gateway-adapter'\nimport type { TurnEventStore } from '../stream/turn-buffer'\nimport type { McpToolDefinition } from '../tools/mcp-rpc'\n\nexport interface PublishedKnowledgePage {\n readonly id: string\n readonly title: string\n readonly text: string\n}\n\n/** A server-created publication. Every selected page's complete text is public. */\nexport interface KnowledgePublication {\n readonly id: string\n readonly revision: string\n readonly ownerId: string\n readonly systemPrompt: string\n read(pageId: string): PublishedKnowledgePage | null\n search(query: string): PublishedKnowledgePage[]\n}\n\n/** Select content at publication time, before any payer or model input exists. */\nexport function createKnowledgePublication(input: {\n id: string\n revision: string\n ownerId: string\n systemPrompt: string\n index: KnowledgeIndex\n pageIds: readonly string[]\n}): KnowledgePublication {\n for (const value of [input.id, input.revision, input.ownerId]) requireIdentity(value)\n const pages: KnowledgePage[] = []\n for (const id of new Set(input.pageIds)) {\n const matches = input.index.pages.filter(page => page.id === id)\n if (matches.length !== 1) throw new Error('Publication page must resolve exactly once')\n const page = matches[0]!\n // Owner metadata, paths, links and source records can refer to private resources.\n pages.push({ id: page.id, title: page.title, text: page.text, path: page.id,\n frontmatter: {}, sourceIds: [], tags: [], outLinks: [] })\n }\n const index: KnowledgeIndex = { root: '', generatedAt: '', sources: [], pages, graph: { nodes: [], edges: [] } }\n const publicPage = (page: KnowledgePage): PublishedKnowledgePage =>\n Object.freeze({ id: page.id, title: page.title, text: page.text })\n return Object.freeze({\n id: input.id, revision: input.revision, ownerId: input.ownerId, systemPrompt: input.systemPrompt,\n read: (id: string) => {\n const page = pages.find(candidate => candidate.id === id)\n return page ? publicPage(page) : null\n },\n search: (query: string) => searchKnowledge(index, query, { limit: 10 }).map(hit => publicPage(hit.page)),\n })\n}\n\n/** Authenticated server identity. Never construct this from model arguments or request JSON. */\nexport interface ConsultationConsumer {\n method: string\n consumerId: string\n keyId?: string\n ownerId?: string\n requestId: string\n threadId?: string\n}\n\nexport interface ConsultationAgent {\n id: string\n ownerId: string\n}\n\nexport interface ConsultationIdentity {\n readonly publicationId: string\n readonly publicationRevision: string\n readonly consumerId: string\n readonly paymentMethod: string\n readonly workspaceId: string\n readonly threadId: string\n}\n\nexport interface ConsultationExecutionControl {\n readonly identity: ConsultationIdentity\n readonly signal: AbortSignal\n readonly executionLimits?: Readonly<ChatTurnExecutionLimits>\n}\n\nexport type PreparedConsultationExecution =\n | { status: 'unsupported'; reason: string }\n | { status: 'prepared'; produce(input: ConsultationExecution): ChatTurnRouteProducer | Promise<ChatTurnRouteProducer> }\n\nexport interface ConsultationExecution extends ConsultationExecutionControl {\n readonly identity: ConsultationIdentity\n readonly systemPrompt: string\n readonly prompt: string\n readonly priorMessages: ReadonlyArray<{ role: string; content: string }>\n readonly tools: McpToolDefinition[]\n}\n\nexport interface PublicConsultationOptions {\n /** Resolve only deliberately published snapshots. Return null after revocation. */\n resolvePublication(agentId: string): Promise<KnowledgePublication | null>\n /** Payment authentication does not substitute for this admission decision. */\n allowConsumer(publication: KnowledgePublication, consumer: ConsultationConsumer): Promise<boolean>\n store: ChatTurnMessageStore\n turnStore: TurnEventStore\n /** Shared durable single-flight lock. Use createDurableTurnLock with thread scope. */\n turnLock: ChatTurnLock<void>\n /** Create or read the stored parent row. Return its actual persisted ownership. */\n ensureConversation(identity: ConsultationIdentity): Promise<{ workspaceId: string; threadId: string }>\n /** Prepare without compute. Refuse limits the isolated executor cannot enforce across all model and tool calls. */\n prepareExecution(input: ConsultationExecutionControl): Promise<PreparedConsultationExecution>\n}\n\ninterface GatewayConsultationContext {\n consumerId: string\n paymentMethod: string\n requestId: string\n threadId?: string\n keyInfo: { keyId: string; ownerId?: string } | null\n messages: Array<{ role: string; content: string }>\n}\n\n/** Compose gateway admission, scoped knowledge and the maintained persisted chat route. */\nexport function createPublicConsultation(options: PublicConsultationOptions) {\n if (typeof options.turnLock?.acquire !== 'function' || typeof options.turnLock.release !== 'function') {\n throw new Error('Public consultation requires a shared turn lock')\n }\n async function ownsConversation(identity: ConsultationIdentity) {\n const conversation = await options.ensureConversation(identity)\n return conversation?.workspaceId === identity.workspaceId && conversation.threadId === identity.threadId\n }\n async function resolve(agent: ConsultationAgent, consumer: ConsultationConsumer) {\n requireIdentity(consumer.consumerId)\n requireIdentity(consumer.method)\n requireIdentity(consumer.threadId)\n const publication = await options.resolvePublication(agent.id)\n if (!publication || publication.id !== agent.id || publication.ownerId !== agent.ownerId\n || await options.allowConsumer(publication, consumer) !== true) return null\n const workspaceId = await scopedId([publication.ownerId, publication.id, publication.revision, consumer.method, consumer.consumerId])\n const threadId = await scopedId([workspaceId, consumer.threadId!])\n const identity: ConsultationIdentity = Object.freeze({\n publicationId: publication.id, publicationRevision: publication.revision,\n consumerId: consumer.consumerId, paymentMethod: consumer.method, workspaceId, threadId,\n })\n return { publication, identity }\n }\n\n return {\n async authorizeConsumer(agent: ConsultationAgent, consumer: ConsultationConsumer) {\n const scope = await resolve(agent, consumer)\n return scope\n ? { allow: true as const }\n : { allow: false as const, reason: 'Consultation access denied', code: 'consultation_forbidden' }\n },\n async readKnowledge(agent: ConsultationAgent, consumer: ConsultationConsumer, pageId: string) {\n const scope = await resolve(agent, consumer)\n if (!scope) throw new Error('Consultation access denied')\n return scope.publication.read(pageId)\n },\n async readHistory(agent: ConsultationAgent, consumer: ConsultationConsumer) {\n const scope = await resolve(agent, consumer)\n if (!scope) throw new Error('Consultation access denied')\n if (!await ownsConversation(scope.identity)) throw new Error('Consultation conversation conflict')\n return (await options.store.listMessages(scope.identity.threadId))\n .map(({ role, content }) => ({ role, content }))\n },\n async getSandbox(agent: ConsultationAgent, context?: GatewayConsultationContext) {\n if (!context) throw new Error('Authenticated consultation identity is required')\n const consumer: ConsultationConsumer = {\n consumerId: context.consumerId, method: context.paymentMethod,\n requestId: context.requestId, threadId: context.threadId,\n keyId: context.keyInfo?.keyId, ownerId: context.keyInfo?.ownerId,\n }\n const scope = await resolve(agent, consumer)\n if (!scope) throw new Error('Consultation access denied')\n // Client-supplied history and owner system prompts never enter this producer.\n const prompt = context.messages.filter(message => message.role === 'user').at(-1)?.content\n if (!prompt) throw new Error('Consultation requires a user message')\n type PromptOptions = { signal?: AbortSignal; executionBudget?: ChatTurnExecutionLimits; maxOutputTokens?: number }\n const prepare = async (streamOptions?: PromptOptions) => {\n const signal = streamOptions?.signal ?? new AbortController().signal\n signal.throwIfAborted()\n const supplied = streamOptions?.executionBudget\n const executionLimits = supplied || streamOptions?.maxOutputTokens !== undefined\n ? Object.freeze({ ...supplied, ...(streamOptions?.maxOutputTokens !== undefined\n ? { maxOutputTokens: Math.min(streamOptions.maxOutputTokens, supplied?.maxOutputTokens ?? Infinity) } : {}) })\n : undefined\n if (executionLimits && Object.values(executionLimits).some(value => typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {\n return { status: 'unsupported' as const, reason: 'Invalid consultation execution limits' }\n }\n const control = Object.freeze({ identity: scope.identity, signal, executionLimits })\n const prepared = await options.prepareExecution(control)\n signal.throwIfAborted()\n if (prepared?.status !== 'prepared' || typeof prepared.produce !== 'function') {\n return { status: 'unsupported' as const, reason: prepared?.status === 'unsupported'\n ? prepared.reason : 'Invalid consultation execution preparation' }\n }\n let started = false\n const start = () => {\n signal.throwIfAborted()\n if (started) throw new Error('Consultation execution already started')\n started = true\n const routes = createChatTurnRoutes({\n projectId: 'public-consultation', store: options.store, turnStore: options.turnStore, turnLock: options.turnLock,\n authorize: async ({ intent, body }) => {\n const current = await resolve(agent, consumer)\n if (intent !== 'turn' || !current\n || current.identity.workspaceId !== scope.identity.workspaceId\n || body?.workspaceId !== scope.identity.workspaceId || body.threadId !== scope.identity.threadId) {\n return { ok: false, response: Response.json({ error: 'Consultation access denied' }, { status: 403 }) }\n }\n if (!await ownsConversation(scope.identity)) {\n return { ok: false, response: Response.json({ error: 'Consultation conversation conflict' }, { status: 403 }) }\n }\n return { ok: true, tenantId: scope.identity.workspaceId,\n userId: scope.identity.consumerId, context: undefined }\n },\n produce: args => {\n signal.throwIfAborted()\n return prepared.produce({\n ...control,\n identity: scope.identity, systemPrompt: scope.publication.systemPrompt, prompt,\n priorMessages: args.priorMessages.map(({ role, content }) => ({ role, content })),\n tools: publicationTools(scope.publication, async () => {\n signal.throwIfAborted()\n const current = await resolve(agent, consumer)\n signal.throwIfAborted()\n if (!current || current.identity.workspaceId !== scope.identity.workspaceId) {\n throw new Error('Consultation access denied')\n }\n }),\n })\n },\n })\n return streamChatRouteAsSandboxEvents({\n routes, request: new Request('https://consultation.invalid/internal'),\n payload: { workspaceId: scope.identity.workspaceId, threadId: scope.identity.threadId,\n content: prompt, turnId: consumer.requestId }, signal, executionLimits,\n })\n }\n return { status: 'prepared' as const, start }\n }\n return {\n prepareBudgetedPrompt: (_message: string, streamOptions: PromptOptions) => prepare(streamOptions),\n streamPrompt: async function* (_message: string, streamOptions?: PromptOptions) {\n const prepared = await prepare(streamOptions)\n if (prepared.status !== 'prepared') throw new Error(prepared.reason)\n yield* prepared.start()\n },\n }\n },\n }\n}\n\nfunction publicationTools(publication: KnowledgePublication, authorize: () => Promise<void>): McpToolDefinition[] {\n return [\n { name: 'knowledge_search', description: 'Search published consultation knowledge.',\n inputSchema: { type: 'object', required: ['query'], properties: { query: { type: 'string' } }, additionalProperties: false },\n run: async args => { await authorize(); return publication.search(singleArgument(args, 'query')) } },\n { name: 'knowledge_read', description: 'Read a published page by its exact citation id.',\n inputSchema: { type: 'object', required: ['pageId'], properties: { pageId: { type: 'string' } }, additionalProperties: false },\n run: async args => { await authorize(); return publication.read(singleArgument(args, 'pageId')) } },\n ]\n}\n\nfunction singleArgument(args: Record<string, unknown>, name: string): string {\n const value = args[name]\n if (Object.keys(args).length !== 1 || typeof value !== 'string' || !value.trim() || value.length > 8192) {\n throw new Error('Invalid published knowledge arguments')\n }\n return value\n}\n\nfunction requireIdentity(value: unknown): asserts value is string {\n if (typeof value !== 'string' || !value.trim() || value.length > 512) throw new Error('Invalid consultation identity')\n}\n\nasync function scopedId(parts: string[]): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(JSON.stringify(parts)))\n return `consultation:${Array.from(new Uint8Array(digest), byte => byte.toString(16).padStart(2, '0')).join('')}`\n}\n"],"mappings":"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","names":["page"]}
@@ -11,14 +11,14 @@ import {
11
11
  snapshotFrame,
12
12
  trackIntervals
13
13
  } from "../chunk-BVKQKGRK.js";
14
- import {
15
- assertMediaUrl
16
- } from "../chunk-F7VH4G5C.js";
17
14
  import {
18
15
  MCP_PROTOCOL_VERSIONS,
19
16
  buildScopedMcpServerEntry,
20
17
  createMcpToolHandler
21
18
  } from "../chunk-KBJL6LIW.js";
19
+ import {
20
+ assertMediaUrl
21
+ } from "../chunk-F7VH4G5C.js";
22
22
 
23
23
  // src/sequences/operations.ts
24
24
  var SEQUENCE_OPERATION_TYPES = [
@@ -1,12 +1,12 @@
1
+ import {
2
+ InvitationsPanel
3
+ } from "../chunk-5MI2SKQH.js";
1
4
  import {
2
5
  InviteAcceptPage
3
6
  } from "../chunk-W7P5KV6O.js";
4
7
  import {
5
8
  MembersPanel
6
9
  } from "../chunk-GRDLGQ6A.js";
7
- import {
8
- InvitationsPanel
9
- } from "../chunk-5MI2SKQH.js";
10
10
  import "../chunk-AULM4X7U.js";
11
11
  import "../chunk-6XIAPIW6.js";
12
12
  export {
@@ -127,7 +127,7 @@ import {
127
127
  withoutRecordGridCreated,
128
128
  withoutRecordGridRemoved,
129
129
  withoutRecordGridUpdate
130
- } from "../chunk-NOME5ZPG.js";
130
+ } from "../chunk-IR5OBDO2.js";
131
131
  import {
132
132
  SessionHistoryPanel,
133
133
  formatSessionTimestamp,
@@ -138,6 +138,7 @@ import {
138
138
  import {
139
139
  MENTION_PILL_CLASS
140
140
  } from "../chunk-3HUFJ5LO.js";
141
+ import "../chunk-3UBAO3N5.js";
141
142
  import "../chunk-FBVLEGEG.js";
142
143
  import {
143
144
  EvidenceLineageTable,
@@ -188,16 +189,17 @@ import {
188
189
  usePending,
189
190
  usePopover
190
191
  } from "../chunk-E5HZ4JPA.js";
192
+ import "../chunk-SJWIZT7B.js";
191
193
  import {
192
194
  tabTerminalConnectionId,
193
195
  useSandboxTerminalConnection
194
196
  } from "../chunk-BATKJP3P.js";
195
- import "../chunk-3UBAO3N5.js";
196
- import "../chunk-SJWIZT7B.js";
197
197
  import "../chunk-HZVVO6VR.js";
198
198
  import {
199
199
  ATTACHMENT_ACCEPT
200
200
  } from "../chunk-SUO2R2ET.js";
201
+ import "../chunk-MCYJON3F.js";
202
+ import "../chunk-OU3VTK3I.js";
201
203
  import {
202
204
  attachmentInputToPart,
203
205
  attachmentKindForMime,
@@ -248,8 +250,6 @@ import {
248
250
  stampInteractionAnswers
249
251
  } from "../chunk-M3K2HVQD.js";
250
252
  import "../chunk-YJMCRXQQ.js";
251
- import "../chunk-MCYJON3F.js";
252
- import "../chunk-OU3VTK3I.js";
253
253
  export {
254
254
  ATTACHMENT_ACCEPT,
255
255
  AgentActivityPanel,
@@ -2,6 +2,11 @@ import {
2
2
  parseReviewQueueItem,
3
3
  projectReviewQueue
4
4
  } from "../chunk-GEYACSFW.js";
5
+ import {
6
+ ToolInputError,
7
+ defineAppTool
8
+ } from "../chunk-TX6S7XXU.js";
9
+ import "../chunk-UGWQLQDS.js";
5
10
  import {
6
11
  isWorkProductStatus,
7
12
  parseAgentCheckInput,
@@ -12,11 +17,6 @@ import {
12
17
  unresolvedBlockingExceptions,
13
18
  workProductToPersistedPart
14
19
  } from "../chunk-ZVEEWGDK.js";
15
- import {
16
- ToolInputError,
17
- defineAppTool
18
- } from "../chunk-TX6S7XXU.js";
19
- import "../chunk-UGWQLQDS.js";
20
20
 
21
21
  // src/work-product/claim-support.ts
22
22
  var CURRENCY = /[$€£¥₹]/gu;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-app",
3
- "version": "0.47.4",
3
+ "version": "0.47.5",
4
4
  "packageManager": "pnpm@11.24.0",
5
5
  "description": "Build agent applications with typed chat, tools, sandboxes, integrations, billing, and evaluation.",
6
6
  "keywords": [
@@ -504,6 +504,11 @@
504
504
  "types": "./dist/spend/index.d.ts",
505
505
  "import": "./dist/spend/index.js",
506
506
  "default": "./dist/spend/index.js"
507
+ },
508
+ "./public-consultation": {
509
+ "types": "./dist/public-consultation/index.d.ts",
510
+ "import": "./dist/public-consultation/index.js",
511
+ "default": "./dist/public-consultation/index.js"
507
512
  }
508
513
  },
509
514
  "scripts": {