@tangle-network/agent-app 0.1.0

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 (61) hide show
  1. package/README.md +59 -0
  2. package/dist/billing/index.d.ts +108 -0
  3. package/dist/billing/index.js +7 -0
  4. package/dist/billing/index.js.map +1 -0
  5. package/dist/chunk-45MYQ3GD.js +62 -0
  6. package/dist/chunk-45MYQ3GD.js.map +1 -0
  7. package/dist/chunk-4NXVI7PW.js +32 -0
  8. package/dist/chunk-4NXVI7PW.js.map +1 -0
  9. package/dist/chunk-7P6VIHI4.js +33 -0
  10. package/dist/chunk-7P6VIHI4.js.map +1 -0
  11. package/dist/chunk-C5CREGT2.js +45 -0
  12. package/dist/chunk-C5CREGT2.js.map +1 -0
  13. package/dist/chunk-CN75FIPT.js +61 -0
  14. package/dist/chunk-CN75FIPT.js.map +1 -0
  15. package/dist/chunk-EDIQ6F55.js +274 -0
  16. package/dist/chunk-EDIQ6F55.js.map +1 -0
  17. package/dist/chunk-FS5OUVRB.js +208 -0
  18. package/dist/chunk-FS5OUVRB.js.map +1 -0
  19. package/dist/chunk-GMFPCCQZ.js +245 -0
  20. package/dist/chunk-GMFPCCQZ.js.map +1 -0
  21. package/dist/chunk-L2TG5DBW.js +74 -0
  22. package/dist/chunk-L2TG5DBW.js.map +1 -0
  23. package/dist/chunk-SIDR6BH3.js +57 -0
  24. package/dist/chunk-SIDR6BH3.js.map +1 -0
  25. package/dist/chunk-YGUNTIT5.js +48 -0
  26. package/dist/chunk-YGUNTIT5.js.map +1 -0
  27. package/dist/crypto/index.d.ts +27 -0
  28. package/dist/crypto/index.js +13 -0
  29. package/dist/crypto/index.js.map +1 -0
  30. package/dist/delegation/index.d.ts +50 -0
  31. package/dist/delegation/index.js +11 -0
  32. package/dist/delegation/index.js.map +1 -0
  33. package/dist/eval/index.d.ts +50 -0
  34. package/dist/eval/index.js +17 -0
  35. package/dist/eval/index.js.map +1 -0
  36. package/dist/index.d.ts +13 -0
  37. package/dist/index.js +149 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/integrations/index.d.ts +84 -0
  40. package/dist/integrations/index.js +11 -0
  41. package/dist/integrations/index.js.map +1 -0
  42. package/dist/redact/index.d.ts +22 -0
  43. package/dist/redact/index.js +7 -0
  44. package/dist/redact/index.js.map +1 -0
  45. package/dist/runtime/index.d.ts +219 -0
  46. package/dist/runtime/index.js +17 -0
  47. package/dist/runtime/index.js.map +1 -0
  48. package/dist/stream/index.d.ts +39 -0
  49. package/dist/stream/index.js +35 -0
  50. package/dist/stream/index.js.map +1 -0
  51. package/dist/tangle/index.d.ts +93 -0
  52. package/dist/tangle/index.js +9 -0
  53. package/dist/tangle/index.js.map +1 -0
  54. package/dist/tools/index.d.ts +213 -0
  55. package/dist/tools/index.js +37 -0
  56. package/dist/tools/index.js.map +1 -0
  57. package/dist/types-CeWor4bQ.d.ts +120 -0
  58. package/dist/web/index.d.ts +51 -0
  59. package/dist/web/index.js +15 -0
  60. package/dist/web/index.js.map +1 -0
  61. package/package.json +101 -0
@@ -0,0 +1,50 @@
1
+ import { CompletionRequirement, RuntimeEventLike } from '@tangle-network/agent-eval';
2
+ export { CompletionRequirement, CompletionVerdict, CorrectnessChecker, ProducedState, RuntimeEventLike, SatisfiedBy, TaskGold, createLlmCorrectnessChecker, extractProducedState, verifyCompletion, weightedComposite } from '@tangle-network/agent-eval';
3
+ import { e as AppToolProducedEvent } from '../types-CeWor4bQ.js';
4
+
5
+ /**
6
+ * Eval — the app-shell BRIDGE to `@tangle-network/agent-eval`, not a reimpl.
7
+ *
8
+ * The completion/scoring ENGINE lives in agent-eval (a peer dependency):
9
+ * `verifyCompletion`, `extractProducedState`, `weightedComposite`,
10
+ * `createLlmCorrectnessChecker`, and the `CompletionRequirement` / `TaskGold` /
11
+ * `ProducedState` types — all re-exported here so a consumer has one import
12
+ * root. This module adds only what agent-eval doesn't have and what is
13
+ * app-shell-specific:
14
+ *
15
+ * 1. {@link producedFromToolEvents} — the bridge: turn the structured app-tool
16
+ * side channel's `AppToolProducedEvent`s (from a tool runtime executor's
17
+ * `onProduced`) into the `RuntimeEventLike`s agent-eval's
18
+ * `extractProducedState` consumes. This is the one piece that knows about
19
+ * the app-tool channel, so it belongs here, not in the engine.
20
+ * 2. {@link createTokenRecallChecker} — a deterministic, no-LLM
21
+ * `CorrectnessChecker` (agent-eval ships only the LLM one). For apps/tests
22
+ * that gate completion without a judge call.
23
+ *
24
+ * Full campaigns (persona simulation, traces, scorecards, held-out gates) are
25
+ * agent-eval's `runEvalCampaign` / `AgentDriver` / `BenchmarkRunner` — use them
26
+ * directly; this module composes with them.
27
+ */
28
+
29
+ /**
30
+ * Bridge the app-tool side channel's produced events into the runtime-event
31
+ * shape agent-eval's `extractProducedState` reads. Pipe it:
32
+ * `verifyCompletion(taskGold, extractProducedState(producedFromToolEvents(events)), checker)`
33
+ */
34
+ declare function producedFromToolEvents(events: readonly AppToolProducedEvent[]): RuntimeEventLike[];
35
+ /**
36
+ * A deterministic `CorrectnessChecker` (agent-eval exports only
37
+ * `createLlmCorrectnessChecker`). A produced item fulfils a requirement when
38
+ * its content is substantive and recalls ≥ `minRecall` of the requirement
39
+ * title's significant tokens. No network — the default gate for apps/tests
40
+ * without an LLM judge. Pass to `verifyCompletion` as the checker.
41
+ */
42
+ declare function createTokenRecallChecker(opts?: {
43
+ minRecall?: number;
44
+ minContentLength?: number;
45
+ }): (requirement: CompletionRequirement, content: string) => Promise<{
46
+ correct: boolean;
47
+ reason: string;
48
+ }>;
49
+
50
+ export { createTokenRecallChecker, producedFromToolEvents };
@@ -0,0 +1,17 @@
1
+ import {
2
+ createLlmCorrectnessChecker,
3
+ createTokenRecallChecker,
4
+ extractProducedState,
5
+ producedFromToolEvents,
6
+ verifyCompletion,
7
+ weightedComposite
8
+ } from "../chunk-4NXVI7PW.js";
9
+ export {
10
+ createLlmCorrectnessChecker,
11
+ createTokenRecallChecker,
12
+ extractProducedState,
13
+ producedFromToolEvents,
14
+ verifyCompletion,
15
+ weightedComposite
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,13 @@
1
+ export { APP_TOOL_NAMES, AppToolMcpServer, AppToolName, AppToolRuntimeExecutor, AuthenticateOptions, BuildHttpMcpServerOptions, BuildMcpServerOptions, CapabilityTokenOptions, DEFAULT_APP_TOOL_PATHS, DEFAULT_HEADER_NAMES, DispatchOptions, HandleToolRequestOptions, OpenAIFunctionTool, RuntimeExecutorOptions, ToolAuthResult, ToolHeaderNames, ToolInputError, authenticateToolRequest, buildAppToolMcpServer, buildAppToolOpenAITools, buildHttpMcpServer, createAppToolRuntimeExecutor, createCapabilityToken, dispatchAppTool, handleAppToolRequest, isAppToolName, outcomeStatus, readToolArgs, verifyCapabilityToken } from './tools/index.js';
2
+ export { A as AddCitationArgs, a as AddCitationResult, b as AppToolContext, c as AppToolHandlers, d as AppToolOutcome, e as AppToolProducedEvent, f as AppToolTaxonomy, R as RenderUiArgs, g as RenderUiResult, S as ScheduleFollowupArgs, h as ScheduleFollowupResult, i as SubmitProposalArgs, j as SubmitProposalResult } from './types-CeWor4bQ.js';
3
+ export { BuildDelegationOptions, DELEGATION_MCP_SERVER_KEY, DELEGATION_TOOLS, DelegationMcpServer, buildDelegationMcpServer } from './delegation/index.js';
4
+ export { BrokerToken, BrokerTokenMinter, BrokerTokenProvider, BrokerTokenProviderOptions, ConsentUrlInput, buildConsentUrl, createBrokerTokenProvider } from './tangle/index.js';
5
+ export { AppToolLoopOptions, DEFAULT_TANGLE_ROUTER_BASE_URL, LoopEvent, LoopToolCall, OpenAICompatStreamTurnOptions, OpenAIStreamChunk, ResolveModelOptions, StreamAppToolLoopOptions, StreamLoopYield, TangleModelConfig, ToolLoopResult, createOpenAICompatStreamTurn, resolveTangleModelConfig, runAppToolLoop, streamAppToolLoop, toLoopEvents } from './runtime/index.js';
6
+ export { createTokenRecallChecker, producedFromToolEvents } from './eval/index.js';
7
+ export { KeyCrypto, KeyProvisioner, WorkspaceKeyManager, WorkspaceKeyManagerOptions, WorkspaceKeyRecord, WorkspaceKeyStore, WorkspaceModelKeyUsage, createWorkspaceKeyManager } from './billing/index.js';
8
+ export { createFieldCrypto, decodeHexKey, decryptAesGcm, encryptAesGcm } from './crypto/index.js';
9
+ export { JsonRecord, PersistedChatMessageForTurn, ResolvedChatTurn, StreamEvent, asRecord, asString, buildUserTextParts, encodeEvent, finalizeAssistantParts, getPartKey, mergePersistedPart, messageHasTurnId, normalizeClientTurnId, normalizePersistedPart, normalizeTime, normalizeToolEvent, resolveChatTurn, resolveToolId, resolveToolName } from './stream/index.js';
10
+ export { HubExecClient, HubExecClientOptions, HubExecErrorCode, HubExecResult, HubInvokeDeps, HubInvokeInput, HubInvokeOutcome, ParsedIntegrationAction, invokeIntegrationHub, resolveIntegrationAction } from './integrations/index.js';
11
+ export { JsonObject, KvLike, RateLimitResult, RequestContext, SecurityHeaderOptions, addSecurityHeaders, checkRateLimit, extractRequestContext, parseJsonObjectBody, requireString } from './web/index.js';
12
+ export { redactForIngestion } from './redact/index.js';
13
+ export { CompletionRequirement, CompletionVerdict, CorrectnessChecker, ProducedState, RuntimeEventLike, SatisfiedBy, TaskGold, createLlmCorrectnessChecker, extractProducedState, verifyCompletion, weightedComposite } from '@tangle-network/agent-eval';
package/dist/index.js ADDED
@@ -0,0 +1,149 @@
1
+ import {
2
+ asRecord,
3
+ asString,
4
+ buildUserTextParts,
5
+ encodeEvent,
6
+ finalizeAssistantParts,
7
+ getPartKey,
8
+ mergePersistedPart,
9
+ messageHasTurnId,
10
+ normalizeClientTurnId,
11
+ normalizePersistedPart,
12
+ normalizeTime,
13
+ normalizeToolEvent,
14
+ resolveChatTurn,
15
+ resolveToolId,
16
+ resolveToolName
17
+ } from "./chunk-GMFPCCQZ.js";
18
+ import {
19
+ HubExecClient,
20
+ invokeIntegrationHub,
21
+ resolveIntegrationAction
22
+ } from "./chunk-L2TG5DBW.js";
23
+ import {
24
+ addSecurityHeaders,
25
+ checkRateLimit,
26
+ extractRequestContext,
27
+ parseJsonObjectBody,
28
+ requireString
29
+ } from "./chunk-CN75FIPT.js";
30
+ import {
31
+ redactForIngestion
32
+ } from "./chunk-C5CREGT2.js";
33
+ import {
34
+ APP_TOOL_NAMES,
35
+ DEFAULT_APP_TOOL_PATHS,
36
+ DEFAULT_HEADER_NAMES,
37
+ ToolInputError,
38
+ authenticateToolRequest,
39
+ buildAppToolMcpServer,
40
+ buildAppToolOpenAITools,
41
+ buildHttpMcpServer,
42
+ createAppToolRuntimeExecutor,
43
+ createCapabilityToken,
44
+ dispatchAppTool,
45
+ handleAppToolRequest,
46
+ isAppToolName,
47
+ outcomeStatus,
48
+ readToolArgs,
49
+ verifyCapabilityToken
50
+ } from "./chunk-EDIQ6F55.js";
51
+ import {
52
+ DELEGATION_MCP_SERVER_KEY,
53
+ DELEGATION_TOOLS,
54
+ buildDelegationMcpServer
55
+ } from "./chunk-7P6VIHI4.js";
56
+ import {
57
+ buildConsentUrl,
58
+ createBrokerTokenProvider
59
+ } from "./chunk-YGUNTIT5.js";
60
+ import {
61
+ DEFAULT_TANGLE_ROUTER_BASE_URL,
62
+ createOpenAICompatStreamTurn,
63
+ resolveTangleModelConfig,
64
+ runAppToolLoop,
65
+ streamAppToolLoop,
66
+ toLoopEvents
67
+ } from "./chunk-FS5OUVRB.js";
68
+ import {
69
+ createLlmCorrectnessChecker,
70
+ createTokenRecallChecker,
71
+ extractProducedState,
72
+ producedFromToolEvents,
73
+ verifyCompletion,
74
+ weightedComposite
75
+ } from "./chunk-4NXVI7PW.js";
76
+ import {
77
+ createWorkspaceKeyManager
78
+ } from "./chunk-45MYQ3GD.js";
79
+ import {
80
+ createFieldCrypto,
81
+ decodeHexKey,
82
+ decryptAesGcm,
83
+ encryptAesGcm
84
+ } from "./chunk-SIDR6BH3.js";
85
+ export {
86
+ APP_TOOL_NAMES,
87
+ DEFAULT_APP_TOOL_PATHS,
88
+ DEFAULT_HEADER_NAMES,
89
+ DEFAULT_TANGLE_ROUTER_BASE_URL,
90
+ DELEGATION_MCP_SERVER_KEY,
91
+ DELEGATION_TOOLS,
92
+ HubExecClient,
93
+ ToolInputError,
94
+ addSecurityHeaders,
95
+ asRecord,
96
+ asString,
97
+ authenticateToolRequest,
98
+ buildAppToolMcpServer,
99
+ buildAppToolOpenAITools,
100
+ buildConsentUrl,
101
+ buildDelegationMcpServer,
102
+ buildHttpMcpServer,
103
+ buildUserTextParts,
104
+ checkRateLimit,
105
+ createAppToolRuntimeExecutor,
106
+ createBrokerTokenProvider,
107
+ createCapabilityToken,
108
+ createFieldCrypto,
109
+ createLlmCorrectnessChecker,
110
+ createOpenAICompatStreamTurn,
111
+ createTokenRecallChecker,
112
+ createWorkspaceKeyManager,
113
+ decodeHexKey,
114
+ decryptAesGcm,
115
+ dispatchAppTool,
116
+ encodeEvent,
117
+ encryptAesGcm,
118
+ extractProducedState,
119
+ extractRequestContext,
120
+ finalizeAssistantParts,
121
+ getPartKey,
122
+ handleAppToolRequest,
123
+ invokeIntegrationHub,
124
+ isAppToolName,
125
+ mergePersistedPart,
126
+ messageHasTurnId,
127
+ normalizeClientTurnId,
128
+ normalizePersistedPart,
129
+ normalizeTime,
130
+ normalizeToolEvent,
131
+ outcomeStatus,
132
+ parseJsonObjectBody,
133
+ producedFromToolEvents,
134
+ readToolArgs,
135
+ redactForIngestion,
136
+ requireString,
137
+ resolveChatTurn,
138
+ resolveIntegrationAction,
139
+ resolveTangleModelConfig,
140
+ resolveToolId,
141
+ resolveToolName,
142
+ runAppToolLoop,
143
+ streamAppToolLoop,
144
+ toLoopEvents,
145
+ verifyCapabilityToken,
146
+ verifyCompletion,
147
+ weightedComposite
148
+ };
149
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,84 @@
1
+ /** `{ success: false }` codes the hub returns on `/exec`. */
2
+ type HubExecErrorCode = 'HUB_APPROVAL_REQUIRED' | 'HUB_POLICY_DENIED' | 'HUB_CONNECTION_MISSING' | 'HUB_CONNECTION_REVOKED' | 'HUB_CONFIG_MISSING' | 'HUB_NOT_FOUND' | string;
3
+ /** Outcome of a hub `/exec` call. Callers MUST inspect `succeeded` before
4
+ * reading `result` — a denied or approval-gated write resolves with
5
+ * `succeeded: false` and a populated `code`, never a thrown silent failure. */
6
+ type HubExecResult = {
7
+ succeeded: true;
8
+ result: unknown;
9
+ } | {
10
+ succeeded: false;
11
+ code: HubExecErrorCode;
12
+ message: string;
13
+ approval?: unknown;
14
+ };
15
+ interface HubExecClientOptions {
16
+ /** Platform base URL (e.g. `TANGLE_PLATFORM_URL`). */
17
+ baseUrl: string;
18
+ /** Calling user's Tangle API key — the hub principal bearer. */
19
+ bearer: string;
20
+ /** Test seam. Defaults to global `fetch`. */
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ /** The provider/connector/action a hub action path addresses, plus the dotted
24
+ * `path` the hub `/exec` endpoint expects. */
25
+ interface ParsedIntegrationAction {
26
+ providerId: string;
27
+ connectorId: string;
28
+ actionId: string;
29
+ /** `provider.connector.action`. */
30
+ path: string;
31
+ }
32
+ /**
33
+ * Resolve an MCP tool name (the opaque `int_…` catalog name the agent calls)
34
+ * into the dotted hub action path. Returns `undefined` when the name is not a
35
+ * catalog integration tool, so the chat loop routes non-integration calls
36
+ * elsewhere instead of misrouting them to the hub.
37
+ */
38
+ declare function resolveIntegrationAction(toolName: string): ParsedIntegrationAction | undefined;
39
+ /** Typed client over the platform hub `/v1/hub/exec`. The hub holds the user's
40
+ * credentials, resolves the connection from the bearer principal, evaluates
41
+ * per-action policy (read → allow, write/destructive → approval), and runs the
42
+ * action server-side. Never throws on a policy block — a gated write is a
43
+ * normal `succeeded: false` outcome. */
44
+ declare class HubExecClient {
45
+ private readonly baseUrl;
46
+ private readonly bearer;
47
+ private readonly fetchImpl;
48
+ constructor(options: HubExecClientOptions);
49
+ exec(input: {
50
+ path: string;
51
+ actionInput?: unknown;
52
+ connectionId?: string;
53
+ }): Promise<HubExecResult>;
54
+ private readEnvelope;
55
+ }
56
+ interface HubInvokeInput {
57
+ userId: string;
58
+ /** The MCP tool name the agent called (`int_<provider>_<connector>_<action>`). */
59
+ toolName: string;
60
+ args?: Record<string, unknown>;
61
+ }
62
+ interface HubInvokeOutcome {
63
+ status: number;
64
+ body: Record<string, unknown>;
65
+ }
66
+ interface HubInvokeDeps {
67
+ /** Resolve the user's Tangle API key (the hub principal bearer). Required —
68
+ * the product binds its own session-key resolver. Null → user not linked. */
69
+ apiKeyResolver: (userId: string) => Promise<string | null>;
70
+ /** Platform base URL. Defaults to `env.TANGLE_PLATFORM_URL`. */
71
+ baseUrl?: string;
72
+ fetchImpl?: typeof fetch;
73
+ env?: Record<string, string | undefined>;
74
+ }
75
+ /**
76
+ * Resolve + execute one integration tool call through the hub: resolve the
77
+ * per-user bearer, map the MCP tool name to the hub action path, forward to
78
+ * `/v1/hub/exec`, and shape the route response (200 ok / 401 not-linked /
79
+ * 400 unknown-tool / 409 approval-required / 502 hub-error). A write that's
80
+ * approval-gated surfaces verbatim as 409, never silently executed.
81
+ */
82
+ declare function invokeIntegrationHub(input: HubInvokeInput, deps: HubInvokeDeps): Promise<HubInvokeOutcome>;
83
+
84
+ export { HubExecClient, type HubExecClientOptions, type HubExecErrorCode, type HubExecResult, type HubInvokeDeps, type HubInvokeInput, type HubInvokeOutcome, type ParsedIntegrationAction, invokeIntegrationHub, resolveIntegrationAction };
@@ -0,0 +1,11 @@
1
+ import {
2
+ HubExecClient,
3
+ invokeIntegrationHub,
4
+ resolveIntegrationAction
5
+ } from "../chunk-L2TG5DBW.js";
6
+ export {
7
+ HubExecClient,
8
+ invokeIntegrationHub,
9
+ resolveIntegrationAction
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * PII redaction for production trace payloads.
3
+ *
4
+ * The chat-trace emission sites pass tool args + results — and at one
5
+ * point the LLM span carried the system prompt + user message verbatim
6
+ * — through the wire. Anything that lands in the ingestion store is
7
+ * also fair game for the analyst-loop's LLM prompts, so personal
8
+ * identifiers MUST be stripped before they leave the request path.
9
+ *
10
+ * Discipline:
11
+ * - Match cheap, deterministic patterns at the string level (SSN, EIN).
12
+ * - Match well-known sensitive object keys (case-insensitive) and
13
+ * replace the value, never the key, so the shape of the object
14
+ * remains debuggable.
15
+ * - Recurse arrays + plain objects only; pass through everything else
16
+ * unchanged (numbers, booleans, null, undefined, functions, etc).
17
+ * - NEVER throw — a redaction failure must not crash the chat handler.
18
+ * Unrecognized inputs round-trip as-is.
19
+ */
20
+ declare function redactForIngestion(value: unknown): unknown;
21
+
22
+ export { redactForIngestion };
@@ -0,0 +1,7 @@
1
+ import {
2
+ redactForIngestion
3
+ } from "../chunk-C5CREGT2.js";
4
+ export {
5
+ redactForIngestion
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,219 @@
1
+ import { d as AppToolOutcome } from '../types-CeWor4bQ.js';
2
+
3
+ /**
4
+ * Resolve the model config a Tangle agent's sandbox/runtime runs on.
5
+ *
6
+ * Every Tangle agent product resolves the SAME thing from env: the Tangle Router
7
+ * (OpenAI-compatible, metered at the platform markup against a single
8
+ * `TANGLE_API_KEY`) by default, with a direct-Anthropic BYOK escape hatch. The
9
+ * shape feeds the sandbox SDK's `backend.model`. Lifted here so no product
10
+ * hand-rolls the env parsing + the router default.
11
+ */
12
+ interface TangleModelConfig {
13
+ /** The Tangle Router is OpenAI-compatible → driven via `openai-compat`.
14
+ * `anthropic` is the BYOK escape hatch. */
15
+ provider: 'openai-compat' | 'anthropic';
16
+ model: string;
17
+ apiKey: string;
18
+ baseUrl: string;
19
+ }
20
+ interface ResolveModelOptions {
21
+ /** Env to read (defaults to process.env). */
22
+ env?: Record<string, string | undefined>;
23
+ /** Router base URL default when `TANGLE_ROUTER_BASE_URL` is unset. */
24
+ defaultRouterBaseUrl?: string;
25
+ }
26
+ declare const DEFAULT_TANGLE_ROUTER_BASE_URL = "https://router.tangle.tools/v1";
27
+ /**
28
+ * Resolve the model config from env. DEFAULT path (`MODEL_PROVIDER` unset or
29
+ * `openai-compat`/`tangle-router`/`tcloud`): the Tangle Router, authenticated
30
+ * with `TANGLE_API_KEY`, model from `MODEL_NAME`. BYOK path
31
+ * (`MODEL_PROVIDER=anthropic`): direct Anthropic with `ANTHROPIC_API_KEY` +
32
+ * `ANTHROPIC_BASE_URL`. Throws (fail-loud) on a missing required var so a
33
+ * misconfigured deploy fails at boot, not mid-turn.
34
+ */
35
+ declare function resolveTangleModelConfig(opts?: ResolveModelOptions): TangleModelConfig;
36
+
37
+ /**
38
+ * OpenAI-compatible stream → `LoopEvent` adapter, for NON-sandbox copilots.
39
+ *
40
+ * `streamAppToolLoop` takes a `streamTurn` seam that yields `LoopEvent`s. A
41
+ * sandboxed agent produces those from its container; a browser/edge copilot
42
+ * instead calls a model directly. The Tangle Router, the tcloud SDK, and most
43
+ * providers all speak the OpenAI Chat Completions streaming shape — so the ONE
44
+ * reusable piece is assembling that stream (content deltas + FRAGMENTED
45
+ * tool-call deltas) into `LoopEvent`s. That assembly is the boilerplate every
46
+ * copilot would re-write (and get wrong — OpenAI streams tool-call arguments in
47
+ * pieces across chunks).
48
+ *
49
+ * This does NOT implement an HTTP client beyond a minimal `fetch` + SSE reader
50
+ * (browser/edge/Node-safe, zero deps). For richer transport use the tcloud SDK
51
+ * or the Vercel AI SDK and pipe their stream through {@link toLoopEvents}.
52
+ */
53
+
54
+ /** Minimal OpenAI Chat Completions streaming chunk (structural — no `openai` dep). */
55
+ interface OpenAIStreamChunk {
56
+ choices?: Array<{
57
+ delta?: {
58
+ content?: string | null;
59
+ tool_calls?: Array<{
60
+ index: number;
61
+ id?: string;
62
+ function?: {
63
+ name?: string;
64
+ arguments?: string;
65
+ };
66
+ }>;
67
+ };
68
+ finish_reason?: string | null;
69
+ }>;
70
+ }
71
+ /**
72
+ * Map an OpenAI-compat streaming chunk iterator to `LoopEvent`s: each content
73
+ * delta → a `text` event; tool-call deltas are accumulated by index across
74
+ * chunks and emitted as one complete `tool_call` event when the stream finishes
75
+ * (arguments JSON-parsed; an empty/garbled args string yields `{}` rather than
76
+ * throwing). Works for the Tangle Router, tcloud, or any OpenAI-compat source.
77
+ */
78
+ declare function toLoopEvents(chunks: AsyncIterable<OpenAIStreamChunk>): AsyncIterable<LoopEvent>;
79
+ interface OpenAICompatStreamTurnOptions {
80
+ /** OpenAI-compat base URL (e.g. the Tangle Router `https://router.tangle.tools/v1`). */
81
+ baseUrl: string;
82
+ apiKey: string;
83
+ model: string;
84
+ /** OpenAI tool definitions — pass `buildAppToolOpenAITools(taxonomy)` so the
85
+ * model can call the app tools. Omit for a tool-free copilot. */
86
+ tools?: unknown[];
87
+ temperature?: number;
88
+ fetchImpl?: typeof fetch;
89
+ /** Extra body fields (e.g. `max_tokens`). */
90
+ extraBody?: Record<string, unknown>;
91
+ }
92
+ /**
93
+ * Build a `streamTurn` that calls an OpenAI-compatible `/chat/completions`
94
+ * endpoint (Tangle Router / tcloud / any compat provider) with `stream: true`
95
+ * and yields `LoopEvent`s via {@link toLoopEvents}. Browser/edge/Node-safe —
96
+ * just `fetch` + an SSE reader. Drop straight into `streamAppToolLoop`:
97
+ *
98
+ * const cfg = resolveTangleModelConfig() // or { baseUrl, apiKey, model }
99
+ * streamAppToolLoop({ streamTurn: createOpenAICompatStreamTurn({ ...cfg, tools }), executeToolCall, ... })
100
+ */
101
+ declare function createOpenAICompatStreamTurn(opts: OpenAICompatStreamTurnOptions): (messages: Array<{
102
+ role: string;
103
+ content: string;
104
+ }>) => AsyncIterable<LoopEvent>;
105
+
106
+ interface LoopToolCall {
107
+ toolCallId?: string;
108
+ toolName: string;
109
+ args: Record<string, unknown>;
110
+ }
111
+ /** Events a turn stream yields. `text` accumulates into the final answer;
112
+ * `tool_call` is collected for dispatch. Extra event types pass through
113
+ * untouched (the caller re-emits them to its own UI stream). */
114
+ type LoopEvent = {
115
+ type: 'text';
116
+ text: string;
117
+ } | {
118
+ type: 'tool_call';
119
+ call: LoopToolCall;
120
+ } | {
121
+ type: 'other';
122
+ event: unknown;
123
+ };
124
+ interface ToolLoopResult {
125
+ /** The model's final text across the loop. */
126
+ finalText: string;
127
+ /** Every tool call executed, with its outcome, in order. */
128
+ toolResults: Array<{
129
+ call: LoopToolCall;
130
+ label: string;
131
+ outcome: AppToolOutcome;
132
+ }>;
133
+ /** Number of model turns run (1 + tool-driven re-runs). */
134
+ turns: number;
135
+ /** True when the loop stopped because it hit `maxToolTurns` with calls still pending. */
136
+ cappedOut: boolean;
137
+ }
138
+ interface AppToolLoopOptions {
139
+ systemPrompt: string;
140
+ userMessage: string;
141
+ priorMessages?: Array<{
142
+ role: string;
143
+ content: string;
144
+ }>;
145
+ /** Stream one model turn over the running message list. The app wraps its
146
+ * backend here. */
147
+ streamTurn: (messages: Array<{
148
+ role: string;
149
+ content: string;
150
+ }>) => AsyncIterable<LoopEvent>;
151
+ /** Execute one tool call. The app routes to its integration executor / app-tool
152
+ * executor and returns the outcome. */
153
+ executeToolCall: (call: LoopToolCall) => Promise<AppToolOutcome>;
154
+ /** Which emitted tool names are executable (others are ignored — e.g. a UI-only
155
+ * tool the app renders but doesn't run here). */
156
+ isExecutableTool: (toolName: string) => boolean;
157
+ /** Max tool-driven re-runs. Default 8. */
158
+ maxToolTurns?: number;
159
+ /** Render one tool outcome as a line the next turn's message carries. Default
160
+ * is a compact `- <label> → ok/failed: …`. */
161
+ renderResult?: (label: string, outcome: AppToolOutcome) => string;
162
+ /** Map a tool call to the label its result is keyed under (default: toolName). */
163
+ labelFor?: (call: LoopToolCall) => string;
164
+ }
165
+ /**
166
+ * Run the bounded tool loop and return the final text + every executed tool
167
+ * outcome. Yields nothing — it's an awaitable driver; callers that need to
168
+ * re-emit events to a UI stream should do so inside `streamTurn`. (A streaming
169
+ * variant can wrap this later; keeping the core awaitable makes it trivially
170
+ * testable.)
171
+ */
172
+ declare function runAppToolLoop(opts: AppToolLoopOptions): Promise<ToolLoopResult>;
173
+ type StreamLoopYield<Raw> = {
174
+ kind: 'event';
175
+ event: Raw;
176
+ } | {
177
+ kind: 'tool_result';
178
+ toolName: string;
179
+ toolCallId?: string;
180
+ label: string;
181
+ outcome: AppToolOutcome;
182
+ } | {
183
+ kind: 'capped';
184
+ pending: number;
185
+ };
186
+ interface StreamAppToolLoopOptions<Raw> {
187
+ systemPrompt: string;
188
+ userMessage: string;
189
+ priorMessages?: Array<{
190
+ role: string;
191
+ content: string;
192
+ }>;
193
+ /** Stream one model turn (the app wraps its backend / runAgentTaskStream). */
194
+ streamTurn: (messages: Array<{
195
+ role: string;
196
+ content: string;
197
+ }>) => AsyncIterable<Raw>;
198
+ /** Text contribution of a raw event, '' if none — used to record the
199
+ * assistant's turn so the next turn has its context. */
200
+ extractText: (event: Raw) => string;
201
+ /** The tool call a raw event represents, or null. */
202
+ extractToolCall: (event: Raw) => LoopToolCall | null;
203
+ /** Which tool names are executable here (others pass through, unexecuted). */
204
+ isExecutableTool: (toolName: string) => boolean;
205
+ /** Execute one call — the app routes to its integration / app-tool executor. */
206
+ executeToolCall: (call: LoopToolCall) => Promise<AppToolOutcome>;
207
+ maxToolTurns?: number;
208
+ renderResult?: (label: string, outcome: AppToolOutcome) => string;
209
+ labelFor?: (call: LoopToolCall) => string;
210
+ }
211
+ /**
212
+ * The streaming bounded tool loop. Yields `event` for each raw turn event and
213
+ * `tool_result` for each executed tool; emits a single `capped` when it stops at
214
+ * the turn limit with calls still pending. The app drives telemetry + UI
215
+ * emission off the yielded items.
216
+ */
217
+ declare function streamAppToolLoop<Raw>(opts: StreamAppToolLoopOptions<Raw>): AsyncGenerator<StreamLoopYield<Raw>, void, unknown>;
218
+
219
+ export { type AppToolLoopOptions, DEFAULT_TANGLE_ROUTER_BASE_URL, type LoopEvent, type LoopToolCall, type OpenAICompatStreamTurnOptions, type OpenAIStreamChunk, type ResolveModelOptions, type StreamAppToolLoopOptions, type StreamLoopYield, type TangleModelConfig, type ToolLoopResult, createOpenAICompatStreamTurn, resolveTangleModelConfig, runAppToolLoop, streamAppToolLoop, toLoopEvents };
@@ -0,0 +1,17 @@
1
+ import {
2
+ DEFAULT_TANGLE_ROUTER_BASE_URL,
3
+ createOpenAICompatStreamTurn,
4
+ resolveTangleModelConfig,
5
+ runAppToolLoop,
6
+ streamAppToolLoop,
7
+ toLoopEvents
8
+ } from "../chunk-FS5OUVRB.js";
9
+ export {
10
+ DEFAULT_TANGLE_ROUTER_BASE_URL,
11
+ createOpenAICompatStreamTurn,
12
+ resolveTangleModelConfig,
13
+ runAppToolLoop,
14
+ streamAppToolLoop,
15
+ toLoopEvents
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,39 @@
1
+ type JsonRecord = Record<string, unknown>;
2
+ interface StreamEvent {
3
+ type: string;
4
+ data?: JsonRecord;
5
+ }
6
+ declare function asRecord(value: unknown): JsonRecord | undefined;
7
+ declare function asString(value: unknown): string | undefined;
8
+ declare function resolveToolId(part: JsonRecord): string;
9
+ declare function resolveToolName(part: JsonRecord): string;
10
+ declare function normalizeTime(value: unknown): JsonRecord | undefined;
11
+ declare function normalizeToolEvent(event: StreamEvent): StreamEvent;
12
+ declare function normalizePersistedPart(rawPart: JsonRecord): JsonRecord | null;
13
+ declare function getPartKey(part: JsonRecord): string;
14
+ declare function mergePersistedPart(existing: JsonRecord | undefined, incoming: JsonRecord, delta?: string): JsonRecord;
15
+ declare function finalizeAssistantParts(partOrder: string[], partMap: Map<string, JsonRecord>, finalText: string): JsonRecord[];
16
+ declare function encodeEvent(encoder: TextEncoder, event: StreamEvent): Uint8Array;
17
+
18
+ interface PersistedChatMessageForTurn {
19
+ id: string;
20
+ role: 'user' | 'assistant' | 'system' | 'tool';
21
+ content: string;
22
+ parts: Array<Record<string, unknown>> | null;
23
+ }
24
+ interface ResolvedChatTurn {
25
+ turnIndex: number;
26
+ shouldInsertUserMessage: boolean;
27
+ priorMessages: PersistedChatMessageForTurn[];
28
+ userParts: JsonRecord[];
29
+ }
30
+ declare function normalizeClientTurnId(value: unknown): string | undefined;
31
+ declare function buildUserTextParts(text: string, turnId: string | undefined): JsonRecord[];
32
+ declare function messageHasTurnId(message: PersistedChatMessageForTurn, turnId: string): boolean;
33
+ declare function resolveChatTurn(input: {
34
+ existingMessages: PersistedChatMessageForTurn[];
35
+ userContent: string;
36
+ turnId?: string;
37
+ }): ResolvedChatTurn;
38
+
39
+ export { type JsonRecord, type PersistedChatMessageForTurn, type ResolvedChatTurn, type StreamEvent, asRecord, asString, buildUserTextParts, encodeEvent, finalizeAssistantParts, getPartKey, mergePersistedPart, messageHasTurnId, normalizeClientTurnId, normalizePersistedPart, normalizeTime, normalizeToolEvent, resolveChatTurn, resolveToolId, resolveToolName };