@truefoundry/assistant-ui-runtime 0.1.15 → 0.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -3
- package/dist/index.js +10 -56
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-VU3Fc17W.d.ts → types-CctJojlz.d.ts} +61 -54
- package/package.json +1 -1
- package/src/convertTurnMessages.test.ts +211 -43
- package/src/convertTurnMessages.ts +17 -72
- package/src/index.ts +2 -0
- package/src/server/index.ts +2 -0
- package/src/server/types.ts +116 -90
- package/src/types.ts +0 -1
- package/src/useTrueFoundryAgentMessages.test.tsx +30 -26
- package/src/useTrueFoundryAgentMessages.ts +6 -13
- package/src/useTrueFoundryAgentRuntime.ts +0 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AgentSessionClient } from 'truefoundry-gateway-sdk/agents';
|
|
2
2
|
import { PrivateAgentSessionClient } from 'truefoundry-gateway-sdk/agents/private';
|
|
3
|
-
import { A as AgentSpec, N as CreateSessionRequest, Y as ListSessionsParams, S as Session, d as Turn,
|
|
3
|
+
import { A as AgentSpec, N as CreateSessionRequest, Y as ListSessionsParams, S as Session, d as Turn, aE as TurnState, a as AgentChatServer, aM as UpdateSessionRequest, k as AgentSelectorEntry, G as ConnectorSelectorEntry, a8 as ModelSelectorEntry, az as SkillSelectorEntry, g as AgentBuilderServer } from '../../types-CctJojlz.js';
|
|
4
4
|
import { TruefoundryGatewayApi } from 'truefoundry-gateway-sdk';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { aH as TurnStreamingEvent, aO as DeltaEvents, T as TurnEvent } from '../types-CctJojlz.js';
|
|
2
|
+
export { aP as ActionRequiredEvent, f as AgentBuilderCapabilitiesResponse, g as AgentBuilderServer, h as AgentCapabilityConfig, a as AgentChatServer, aQ as AgentInfo, i as AgentLibraryEntry, aR as AgentParent, j as AgentRuntimeConfig, k as AgentSelectorEntry, l as AgentSkill, A as AgentSpec, m as AgentUIServer, n as AgentUIServerPort, o as ApprovalDecision, p as AuthenticateConnectorRequest, C as CatalogServer, aS as ChunkDeltaToolCall, q as ConnectorAuth, r as ConnectorAuthApiKey, s as ConnectorAuthNone, t as ConnectorAuthOAuth, u as ConnectorAuthPublic, v as ConnectorAuthPublicApiKey, w as ConnectorAuthPublicNone, x as ConnectorAuthPublicOAuth, y as ConnectorAuthType, z as ConnectorAuthenticationResult, B as ConnectorBase, D as ConnectorCatalogEntry, E as ConnectorCatalogServer, F as ConnectorConfigBase, G as ConnectorSelectorEntry, H as ConnectorState, I as CreateConnectorRequest, J as CreateModelProviderRequest, K as CreateSandboxProviderRequest, L as CreateSandboxRequest, N as CreateSessionRequest, O as CreateSkillRequest, P as CreateSkillRequestBase, Q as DefinedSkill, R as GithubSkill, V as ImportGithubSkillRequest, W as ListResult, X as ListSessionsOrder, Y as ListSessionsParams, M as McpAuthRequiredEvent, aT as McpInitializeEvent, aU as McpServerAuthInfo, Z as McpServerMount, _ as Model, $ as ModelCatalogServer, a0 as ModelEntry, aV as ModelMessageContentPart, aW as ModelMessageDeltaEvent, a1 as ModelMessageEvent, a2 as ModelParams, a3 as ModelProperties, a4 as ModelProviderBase, a5 as ModelProviderCatalogEntry, a6 as ModelProviderConfigBase, a7 as ModelSelection, a8 as ModelSelectorEntry, a9 as PageParams, aa as PreviousTurnIdInput, ab as ProviderEntry, ac as ProviderType, ad as RegistrySkill, ae as SandboxBase, af as SandboxCatalogEntry, ag as SandboxCatalogServer, ah as SandboxConfig, ai as SandboxCreatedEvent, aj as SandboxProviderBase, ak as SandboxProviderCatalogEntry, al as SandboxProviderConfig, am as SandboxProviderListEntry, an as SandboxSnapshotSyncStatus, ao as SaveAgentRequest, ap as SaveAgentResult, aq as SearchAgentSelectorParams, ar as SearchAgentsParams, as as SelectRegistrySkillRequest, S as Session, at as SessionEventItem, au as SkillBase, av as SkillCatalogEntry, aw as SkillCatalogServer, ax as SkillConfigBase, ay as SkillMount, az as SkillSelectorEntry, b as ThreadCreatedEvent, aX as ThreadDoneEvent, aA as ToolApprovalRequiredEvent, aB as ToolBase, aC as ToolCall, aY as ToolCallFunction, aZ as ToolCallRef, a_ as ToolInfo, a$ as ToolResponseEvent, aD as ToolResponseRequiredEvent, d as Turn, b0 as TurnCreatedEvent, b1 as TurnDoneEvent, e as TurnInputItem, aE as TurnState, b2 as TurnStateCancelled, aF as TurnStateDone, b3 as TurnStateError, b4 as TurnStateRunning, aG as TurnStreamData, aI as UpdateConnectorRequest, aJ as UpdateModelProviderRequest, aK as UpdateSandboxProviderRequest, aL as UpdateSandboxRequest, aM as UpdateSessionRequest, aN as UserMessage, b5 as UserMessageContent, c as UserToolApprovalEvent, U as UserToolResponseEvent } from '../types-CctJojlz.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Local implementations of streaming delta helpers.
|
|
@@ -271,19 +271,19 @@ type SearchAgentSelectorParams = {
|
|
|
271
271
|
offset?: number;
|
|
272
272
|
};
|
|
273
273
|
/**
|
|
274
|
-
* Mounts written to AgentSpec.skills[] / AgentSpec.mcpServers[].
|
|
275
|
-
*
|
|
276
|
-
* These are opaque to the runtime — it stores and forwards them but never reads
|
|
277
|
-
* a field, and the backend owns the shape (the gateway identifies a skill by
|
|
278
|
-
* `fqn`, with no `id` or `name` anywhere). So the base constrains only that a
|
|
279
|
-
* mount is an object; hosts intersect their concrete mount type over it, as
|
|
280
|
-
* `TfySkillMount` / `TfyMcpServerMount` do in the gateway adapter.
|
|
281
|
-
*
|
|
282
|
-
* Naming a field here would not just be unread, it would be wrong: a base with
|
|
283
|
-
* required fields rejects the backend's own payloads, and one with only optional
|
|
284
|
-
* fields is a weak type, which TypeScript rejects for a source that shares no
|
|
285
|
-
* property with it — the gateway's registry skill shares none.
|
|
286
|
-
*/
|
|
274
|
+
* Mounts written to AgentSpec.skills[] / AgentSpec.mcpServers[].
|
|
275
|
+
*
|
|
276
|
+
* These are opaque to the runtime — it stores and forwards them but never reads
|
|
277
|
+
* a field, and the backend owns the shape (the gateway identifies a skill by
|
|
278
|
+
* `fqn`, with no `id` or `name` anywhere). So the base constrains only that a
|
|
279
|
+
* mount is an object; hosts intersect their concrete mount type over it, as
|
|
280
|
+
* `TfySkillMount` / `TfyMcpServerMount` do in the gateway adapter.
|
|
281
|
+
*
|
|
282
|
+
* Naming a field here would not just be unread, it would be wrong: a base with
|
|
283
|
+
* required fields rejects the backend's own payloads, and one with only optional
|
|
284
|
+
* fields is a weak type, which TypeScript rejects for a source that shares no
|
|
285
|
+
* property with it — the gateway's registry skill shares none.
|
|
286
|
+
*/
|
|
287
287
|
type SkillMount = object;
|
|
288
288
|
type McpServerMount = object;
|
|
289
289
|
interface ModelParams {
|
|
@@ -303,10 +303,10 @@ interface AgentRuntimeConfig {
|
|
|
303
303
|
askUserQuestions?: AgentCapabilityConfig;
|
|
304
304
|
}
|
|
305
305
|
/**
|
|
306
|
-
* SDK-owned agent definition — fields the FE reads/writes.
|
|
307
|
-
* Host widens `model` / `skills` / `mcpServers` / `config` via type params,
|
|
308
|
-
* and adds extra fields via `TSpec extends AgentSpec<...>`.
|
|
309
|
-
*/
|
|
306
|
+
* SDK-owned agent definition — fields the FE reads/writes.
|
|
307
|
+
* Host widens `model` / `skills` / `mcpServers` / `config` via type params,
|
|
308
|
+
* and adds extra fields via `TSpec extends AgentSpec<...>`.
|
|
309
|
+
*/
|
|
310
310
|
interface AgentSpec<TModel extends Model = Model, TSkill extends SkillMount = SkillMount, TMcp extends McpServerMount = McpServerMount, TConfig extends AgentRuntimeConfig = AgentRuntimeConfig> {
|
|
311
311
|
model: TModel;
|
|
312
312
|
skills?: TSkill[];
|
|
@@ -413,11 +413,11 @@ interface Turn {
|
|
|
413
413
|
createdAt: string;
|
|
414
414
|
}
|
|
415
415
|
/**
|
|
416
|
-
* Chat / session port — the runtime calls these.
|
|
417
|
-
*
|
|
418
|
-
* All session ops are flat (sessionId param). No gateway client dependency.
|
|
419
|
-
* `createTrueFoundryServer` is one possible implementation (TFY adapter).
|
|
420
|
-
*/
|
|
416
|
+
* Chat / session port — the runtime calls these.
|
|
417
|
+
*
|
|
418
|
+
* All session ops are flat (sessionId param). No gateway client dependency.
|
|
419
|
+
* `createTrueFoundryServer` is one possible implementation (TFY adapter).
|
|
420
|
+
*/
|
|
421
421
|
interface AgentChatServer<TSpec extends AgentSpec = AgentSpec, TSession extends Session<TSpec> = Session<TSpec>, TCreate extends CreateSessionRequest<TSpec> = CreateSessionRequest<TSpec>, TList extends ListSessionsParams = ListSessionsParams, TUpdate extends UpdateSessionRequest<TSpec> = UpdateSessionRequest<TSpec>, TTurn extends Turn = Turn> {
|
|
422
422
|
createSession(req: TCreate): Promise<TSession>;
|
|
423
423
|
listSessions(req?: TList): Promise<ListResult<TSession>>;
|
|
@@ -512,9 +512,9 @@ interface AgentBuilderCapabilitiesResponse {
|
|
|
512
512
|
};
|
|
513
513
|
}
|
|
514
514
|
/**
|
|
515
|
-
* Builder catalog + persist port — atoms call these.
|
|
516
|
-
* Passed separately from the runtime's chat server.
|
|
517
|
-
*/
|
|
515
|
+
* Builder catalog + persist port — atoms call these.
|
|
516
|
+
* Passed separately from the runtime's chat server.
|
|
517
|
+
*/
|
|
518
518
|
interface AgentBuilderServer<TSpec extends AgentSpec = AgentSpec, TModel extends ModelSelectorEntry = ModelSelectorEntry, TSkill extends SkillSelectorEntry = SkillSelectorEntry, TMcp extends ConnectorSelectorEntry = ConnectorSelectorEntry, TAgent extends AgentSelectorEntry = AgentSelectorEntry, TSave = SaveAgentResult, TCapabilities extends AgentBuilderCapabilitiesResponse = AgentBuilderCapabilitiesResponse> {
|
|
519
519
|
getCapabilities(): Promise<TCapabilities>;
|
|
520
520
|
getModels(): Promise<TModel[]>;
|
|
@@ -527,25 +527,25 @@ interface AgentBuilderServer<TSpec extends AgentSpec = AgentSpec, TModel extends
|
|
|
527
527
|
}): Promise<void>;
|
|
528
528
|
}
|
|
529
529
|
/**
|
|
530
|
-
* Provider type id. Reserved literal: `"custom"` for user-defined providers;
|
|
531
|
-
* any other string is a builtin (e.g. `"openai"`, `"anthropic"`).
|
|
532
|
-
*
|
|
533
|
-
* Note: `string | "custom"` is useless in TypeScript (`"custom"` ⊆ `string`),
|
|
534
|
-
* so this stays `string` and `"custom"` is a documented convention.
|
|
535
|
-
*/
|
|
530
|
+
* Provider type id. Reserved literal: `"custom"` for user-defined providers;
|
|
531
|
+
* any other string is a builtin (e.g. `"openai"`, `"anthropic"`).
|
|
532
|
+
*
|
|
533
|
+
* Note: `string | "custom"` is useless in TypeScript (`"custom"` ⊆ `string`),
|
|
534
|
+
* so this stays `string` and `"custom"` is a documented convention.
|
|
535
|
+
*/
|
|
536
536
|
type ProviderType = string;
|
|
537
537
|
/**
|
|
538
|
-
* Model row — form "Model ID" + "Display name".
|
|
539
|
-
* Host extends for properties, etc.
|
|
540
|
-
*/
|
|
538
|
+
* Model row — form "Model ID" + "Display name".
|
|
539
|
+
* Host extends for properties, etc.
|
|
540
|
+
*/
|
|
541
541
|
interface ModelEntry {
|
|
542
542
|
id: string;
|
|
543
543
|
name: string;
|
|
544
544
|
}
|
|
545
545
|
/**
|
|
546
|
-
* Write config for create/update (custom form + catalog "Save key").
|
|
547
|
-
* Host extends. `baseUrl` present iff `type === "custom"`.
|
|
548
|
-
*/
|
|
546
|
+
* Write config for create/update (custom form + catalog "Save key").
|
|
547
|
+
* Host extends. `baseUrl` present iff `type === "custom"`.
|
|
548
|
+
*/
|
|
549
549
|
interface ModelProviderConfigBase<TModel extends ModelEntry = ModelEntry> {
|
|
550
550
|
type: ProviderType;
|
|
551
551
|
name: string;
|
|
@@ -555,9 +555,9 @@ interface ModelProviderConfigBase<TModel extends ModelEntry = ModelEntry> {
|
|
|
555
555
|
models: TModel[];
|
|
556
556
|
}
|
|
557
557
|
/**
|
|
558
|
-
* Configured provider card (list/read). No raw `apiKey`.
|
|
559
|
-
* Host extends for apiKeySet, timestamps, etc.
|
|
560
|
-
*/
|
|
558
|
+
* Configured provider card (list/read). No raw `apiKey`.
|
|
559
|
+
* Host extends for apiKeySet, timestamps, etc.
|
|
560
|
+
*/
|
|
561
561
|
interface ModelProviderBase<TModel extends ModelEntry = ModelEntry> {
|
|
562
562
|
id: string;
|
|
563
563
|
type: ProviderType;
|
|
@@ -567,10 +567,10 @@ interface ModelProviderBase<TModel extends ModelEntry = ModelEntry> {
|
|
|
567
567
|
models: TModel[];
|
|
568
568
|
}
|
|
569
569
|
/**
|
|
570
|
-
* Discovery-only catalog provider (AVAILABLE list).
|
|
571
|
-
* `type` must not be `"custom"` — custom providers use the custom form.
|
|
572
|
-
* Host extends for richer model rows.
|
|
573
|
-
*/
|
|
570
|
+
* Discovery-only catalog provider (AVAILABLE list).
|
|
571
|
+
* `type` must not be `"custom"` — custom providers use the custom form.
|
|
572
|
+
* Host extends for richer model rows.
|
|
573
|
+
*/
|
|
574
574
|
interface ModelProviderCatalogEntry<TModel extends ModelEntry = ModelEntry> {
|
|
575
575
|
type: ProviderType;
|
|
576
576
|
name: string;
|
|
@@ -628,8 +628,8 @@ type ConnectorAuthPublicNone = {
|
|
|
628
628
|
};
|
|
629
629
|
type ConnectorAuthPublic = ConnectorAuthPublicOAuth | ConnectorAuthPublicApiKey | ConnectorAuthPublicNone;
|
|
630
630
|
/**
|
|
631
|
-
* MCP / connector create-edit config. Host extends for extra fields, etc.
|
|
632
|
-
*/
|
|
631
|
+
* MCP / connector create-edit config. Host extends for extra fields, etc.
|
|
632
|
+
*/
|
|
633
633
|
interface ConnectorConfigBase<TAuth extends ConnectorAuth = ConnectorAuth> {
|
|
634
634
|
name: string;
|
|
635
635
|
url: string;
|
|
@@ -749,7 +749,6 @@ interface SkillCatalogServer<TSkill extends SkillBase = SkillBase, TCatalogEntry
|
|
|
749
749
|
}
|
|
750
750
|
/** Mutable sandbox provider settings shared by catalog rows, create, and update. */
|
|
751
751
|
interface SandboxConfig {
|
|
752
|
-
snapshotName: string;
|
|
753
752
|
execTimeoutMs: number;
|
|
754
753
|
autoStopIntervalInMinutes: number;
|
|
755
754
|
autoArchiveIntervalInMinutes: number;
|
|
@@ -770,6 +769,14 @@ interface SandboxBase extends SandboxConfig {
|
|
|
770
769
|
catalogId: string;
|
|
771
770
|
isConnected: boolean;
|
|
772
771
|
}
|
|
772
|
+
type SandboxSnapshotSyncStatus = {
|
|
773
|
+
status: "pending" | "ready" | "failed";
|
|
774
|
+
statusReason?: string | null;
|
|
775
|
+
};
|
|
776
|
+
interface SandboxProviderListEntry<TSandbox extends SandboxBase = SandboxBase> {
|
|
777
|
+
data: TSandbox;
|
|
778
|
+
snapshotSyncStatus: SandboxSnapshotSyncStatus;
|
|
779
|
+
}
|
|
773
780
|
interface CreateSandboxRequest extends SandboxConfig {
|
|
774
781
|
/** `SandboxCatalogEntry.id` used to create this sandbox provider. */
|
|
775
782
|
catalogId: string;
|
|
@@ -788,11 +795,11 @@ type SandboxProviderCatalogEntry = SandboxCatalogEntry;
|
|
|
788
795
|
type SandboxProviderBase = SandboxBase;
|
|
789
796
|
type CreateSandboxProviderRequest = CreateSandboxRequest;
|
|
790
797
|
type UpdateSandboxProviderRequest = UpdateSandboxRequest;
|
|
791
|
-
interface SandboxCatalogServer<TProvider extends SandboxBase = SandboxBase, TCatalogEntry extends SandboxCatalogEntry = SandboxCatalogEntry, TCreate extends CreateSandboxRequest = CreateSandboxRequest, TUpdate extends UpdateSandboxRequest = UpdateSandboxRequest> {
|
|
798
|
+
interface SandboxCatalogServer<TProvider extends SandboxBase = SandboxBase, TCatalogEntry extends SandboxCatalogEntry = SandboxCatalogEntry, TCreate extends CreateSandboxRequest = CreateSandboxRequest, TUpdate extends UpdateSandboxRequest = UpdateSandboxRequest, TListEntry extends SandboxProviderListEntry<TProvider> = SandboxProviderListEntry<TProvider>> {
|
|
792
799
|
getSandboxProviderCatalog(): Promise<TCatalogEntry[]>;
|
|
793
800
|
listSandboxProviders(req?: {
|
|
794
801
|
query?: string;
|
|
795
|
-
}): Promise<
|
|
802
|
+
}): Promise<TListEntry[]>;
|
|
796
803
|
createSandboxProvider(req: TCreate): Promise<TProvider>;
|
|
797
804
|
updateSandboxProvider(req: TUpdate): Promise<TProvider>;
|
|
798
805
|
deleteSandboxProvider?(req: {
|
|
@@ -806,10 +813,10 @@ type ConnectorState = ConnectorSelectorEntry;
|
|
|
806
813
|
type AgentLibraryEntry = AgentSelectorEntry;
|
|
807
814
|
type SearchAgentsParams = SearchAgentSelectorParams;
|
|
808
815
|
/**
|
|
809
|
-
* Settings management aggregate — modelCatalog + connectorCatalog + optional
|
|
810
|
-
* skill and sandbox catalogs.
|
|
811
|
-
* Hosts may pass the whole object to an app shell, or a focused sub-port to a page.
|
|
812
|
-
*/
|
|
816
|
+
* Settings management aggregate — modelCatalog + connectorCatalog + optional
|
|
817
|
+
* skill and sandbox catalogs.
|
|
818
|
+
* Hosts may pass the whole object to an app shell, or a focused sub-port to a page.
|
|
819
|
+
*/
|
|
813
820
|
interface CatalogServer<TModelCatalog extends ModelCatalogServer = ModelCatalogServer, TConnectorCatalog extends ConnectorCatalogServer = ConnectorCatalogServer, TSkillCatalog extends SkillCatalogServer = SkillCatalogServer, TSandboxCatalog extends SandboxCatalogServer = SandboxCatalogServer> {
|
|
814
821
|
modelCatalog: TModelCatalog;
|
|
815
822
|
connectorCatalog: TConnectorCatalog;
|
|
@@ -833,4 +840,4 @@ type AgentUIServerPort<TChat extends AgentChatServer = AgentChatServer, TBuilder
|
|
|
833
840
|
/** Host-facing alias used by trueforge-ui. */
|
|
834
841
|
type AgentUIServer = AgentUIServerPort;
|
|
835
842
|
|
|
836
|
-
export type { ModelCatalogServer as $, AgentSpec as A, ConnectorBase as B, CatalogServer as C, ConnectorCatalogEntry as D, ConnectorCatalogServer as E, ConnectorConfigBase as F, ConnectorSelectorEntry as G, ConnectorState as H, CreateConnectorRequest as I, CreateModelProviderRequest as J, CreateSandboxProviderRequest as K, CreateSandboxRequest as L, McpAuthRequiredEvent as M, CreateSessionRequest as N, CreateSkillRequest as O, CreateSkillRequestBase as P, DefinedSkill as Q, GithubSkill as R, Session as S, TurnEvent as T, UserToolResponseEvent as U, ImportGithubSkillRequest as V, ListResult as W, ListSessionsOrder as X, ListSessionsParams as Y, McpServerMount as Z, Model as _, AgentChatServer as a,
|
|
843
|
+
export type { ModelCatalogServer as $, AgentSpec as A, ConnectorBase as B, CatalogServer as C, ConnectorCatalogEntry as D, ConnectorCatalogServer as E, ConnectorConfigBase as F, ConnectorSelectorEntry as G, ConnectorState as H, CreateConnectorRequest as I, CreateModelProviderRequest as J, CreateSandboxProviderRequest as K, CreateSandboxRequest as L, McpAuthRequiredEvent as M, CreateSessionRequest as N, CreateSkillRequest as O, CreateSkillRequestBase as P, DefinedSkill as Q, GithubSkill as R, Session as S, TurnEvent as T, UserToolResponseEvent as U, ImportGithubSkillRequest as V, ListResult as W, ListSessionsOrder as X, ListSessionsParams as Y, McpServerMount as Z, Model as _, AgentChatServer as a, ToolResponseEvent as a$, ModelEntry as a0, ModelMessageEvent as a1, ModelParams as a2, ModelProperties as a3, ModelProviderBase as a4, ModelProviderCatalogEntry as a5, ModelProviderConfigBase as a6, ModelSelection as a7, ModelSelectorEntry as a8, PageParams as a9, ToolApprovalRequiredEvent as aA, ToolBase as aB, ToolCall as aC, ToolResponseRequiredEvent as aD, TurnState as aE, TurnStateDone as aF, TurnStreamData as aG, TurnStreamingEvent as aH, UpdateConnectorRequest as aI, UpdateModelProviderRequest as aJ, UpdateSandboxProviderRequest as aK, UpdateSandboxRequest as aL, UpdateSessionRequest as aM, UserMessage as aN, DeltaEvents as aO, ActionRequiredEvent as aP, AgentInfo as aQ, AgentParent as aR, ChunkDeltaToolCall as aS, McpInitializeEvent as aT, McpServerAuthInfo as aU, ModelMessageContentPart as aV, ModelMessageDeltaEvent as aW, ThreadDoneEvent as aX, ToolCallFunction as aY, ToolCallRef as aZ, ToolInfo as a_, PreviousTurnIdInput as aa, ProviderEntry as ab, ProviderType as ac, RegistrySkill as ad, SandboxBase as ae, SandboxCatalogEntry as af, SandboxCatalogServer as ag, SandboxConfig as ah, SandboxCreatedEvent as ai, SandboxProviderBase as aj, SandboxProviderCatalogEntry as ak, SandboxProviderConfig as al, SandboxProviderListEntry as am, SandboxSnapshotSyncStatus as an, SaveAgentRequest as ao, SaveAgentResult as ap, SearchAgentSelectorParams as aq, SearchAgentsParams as ar, SelectRegistrySkillRequest as as, SessionEventItem as at, SkillBase as au, SkillCatalogEntry as av, SkillCatalogServer as aw, SkillConfigBase as ax, SkillMount as ay, SkillSelectorEntry as az, ThreadCreatedEvent as b, TurnCreatedEvent as b0, TurnDoneEvent as b1, TurnStateCancelled as b2, TurnStateError as b3, TurnStateRunning as b4, UserMessageContent as b5, UserToolApprovalEvent as c, Turn as d, TurnInputItem as e, AgentBuilderCapabilitiesResponse as f, AgentBuilderServer as g, AgentCapabilityConfig as h, AgentLibraryEntry as i, AgentRuntimeConfig as j, AgentSelectorEntry as k, AgentSkill as l, AgentUIServer as m, AgentUIServerPort as n, ApprovalDecision as o, AuthenticateConnectorRequest as p, ConnectorAuth as q, ConnectorAuthApiKey as r, ConnectorAuthNone as s, ConnectorAuthOAuth as t, ConnectorAuthPublic as u, ConnectorAuthPublicApiKey as v, ConnectorAuthPublicNone as w, ConnectorAuthPublicOAuth as x, ConnectorAuthType as y, ConnectorAuthenticationResult as z };
|
package/package.json
CHANGED
|
@@ -18,8 +18,8 @@ import type {
|
|
|
18
18
|
import { ROOT_THREAD_ID } from "./constants.js";
|
|
19
19
|
import { collectPendingToolResponses } from "./collectPending.js";
|
|
20
20
|
import {
|
|
21
|
-
buildSnapshotBeforeTurnIndex,
|
|
22
21
|
buildSnapshotFromSessionEvents,
|
|
22
|
+
buildSnapshotThroughTurn,
|
|
23
23
|
buildTurnAssistantContent,
|
|
24
24
|
buildUserMessageContent,
|
|
25
25
|
buildUserMessageFromTurnInput,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
prependOlderSessionHistory,
|
|
29
29
|
projectSessionMessages,
|
|
30
30
|
repositoryItemsFromMessages,
|
|
31
|
+
resolveGatewayBranchPreviousTurnIdForTurn,
|
|
31
32
|
streamTurnEvents,
|
|
32
33
|
turnStreamUpdateToAssistantMessage,
|
|
33
34
|
} from "./convertTurnMessages.js";
|
|
@@ -135,22 +136,68 @@ function mockTurn(
|
|
|
135
136
|
};
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
/** Mirror runtime listTurns normalization: ASC stays, DESC (or tied) reverses. */
|
|
140
|
+
function toOldestFirstTurns(turns: TurnFixture[]): TurnFixture[] {
|
|
141
|
+
const chain = turns.filter((turn) => turn.state.status !== "running");
|
|
142
|
+
let newestFirst = chain.length > 1;
|
|
143
|
+
for (let i = 1; i < chain.length; i++) {
|
|
144
|
+
const newer = chain[i];
|
|
145
|
+
const older = chain[i - 1];
|
|
146
|
+
if (newer == null || older == null) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const delta = Date.parse(newer.createdAt) - Date.parse(older.createdAt);
|
|
150
|
+
if (delta < 0) {
|
|
151
|
+
newestFirst = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
if (delta > 0) {
|
|
155
|
+
newestFirst = false;
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return newestFirst ? [...chain].reverse() : [...chain];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Mirrors the host's ancestor walk: parent pointers only, sibling branches excluded. */
|
|
163
|
+
function ancestorChainFromTurns(
|
|
164
|
+
turns: TurnFixture[],
|
|
165
|
+
anchorTurnId: string,
|
|
166
|
+
): TurnFixture[] {
|
|
167
|
+
const turnsById = new Map(turns.map((turn) => [turn.id, turn]));
|
|
168
|
+
const chain: TurnFixture[] = [];
|
|
169
|
+
const seen = new Set<string>();
|
|
170
|
+
let cursor: string | null | undefined = anchorTurnId;
|
|
171
|
+
while (cursor != null && !seen.has(cursor)) {
|
|
172
|
+
seen.add(cursor);
|
|
173
|
+
const turn = turnsById.get(cursor);
|
|
174
|
+
if (turn == null) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (turn.state.status !== "running") {
|
|
178
|
+
chain.unshift(turn);
|
|
179
|
+
}
|
|
180
|
+
cursor = turn.previousTurnId;
|
|
181
|
+
}
|
|
182
|
+
return chain;
|
|
183
|
+
}
|
|
184
|
+
|
|
138
185
|
/**
|
|
139
|
-
* Builds session-level event items from per-turn mocks —
|
|
140
|
-
* running turns excluded (matches session.listEvents
|
|
186
|
+
* Builds session-level event items from per-turn mocks — accepts ASC or DESC
|
|
187
|
+
* listTurns order; running turns excluded (matches session.listEvents). An
|
|
188
|
+
* anchor selects that turn's ancestor chain, not a chronological prefix.
|
|
141
189
|
*/
|
|
142
190
|
function sessionEventItemsFromTurns(
|
|
143
|
-
|
|
191
|
+
turns: TurnFixture[],
|
|
144
192
|
lastTurnId?: string,
|
|
145
193
|
): SessionEventItem[] {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
194
|
+
const chain =
|
|
195
|
+
lastTurnId == null
|
|
196
|
+
? toOldestFirstTurns(turns)
|
|
197
|
+
: ancestorChainFromTurns(turns, lastTurnId);
|
|
151
198
|
|
|
152
199
|
const items: SessionEventItem[] = [];
|
|
153
|
-
for (const turn of
|
|
200
|
+
for (const turn of chain) {
|
|
154
201
|
items.push({
|
|
155
202
|
turnId: turn.id,
|
|
156
203
|
event: {
|
|
@@ -160,6 +207,9 @@ function sessionEventItemsFromTurns(
|
|
|
160
207
|
input: turn.input,
|
|
161
208
|
state: { status: "running" },
|
|
162
209
|
createdAt: turn.createdAt,
|
|
210
|
+
...(turn.previousTurnId === undefined
|
|
211
|
+
? {}
|
|
212
|
+
: { previousTurnId: turn.previousTurnId }),
|
|
163
213
|
},
|
|
164
214
|
});
|
|
165
215
|
for (const event of turn.events) {
|
|
@@ -180,10 +230,18 @@ function sessionEventItemsFromTurns(
|
|
|
180
230
|
|
|
181
231
|
function mockServerWithTurns(turns: TurnFixture[]): AgentChatServer {
|
|
182
232
|
const eventsByTurnId = new Map(turns.map((turn) => [turn.id, turn.events]));
|
|
233
|
+
const turnsById = new Map(turns.map((turn) => [turn.id, turn]));
|
|
183
234
|
return {
|
|
184
235
|
listTurns: async ({ limit }: { limit?: number } = {}) => ({
|
|
185
236
|
data: limit != null ? turns.slice(0, limit) : turns,
|
|
186
237
|
}),
|
|
238
|
+
getTurn: async ({ turnId }: { turnId: string }) => {
|
|
239
|
+
const turn = turnsById.get(turnId);
|
|
240
|
+
if (turn == null) {
|
|
241
|
+
throw new Error(`Turn ${turnId} not found`);
|
|
242
|
+
}
|
|
243
|
+
return turn;
|
|
244
|
+
},
|
|
187
245
|
listEvents: async (opts: { lastTurnId?: string } = {}) => {
|
|
188
246
|
const items = sessionEventItemsFromTurns(turns, opts.lastTurnId);
|
|
189
247
|
const newestFirst = [...items].reverse();
|
|
@@ -2824,40 +2882,46 @@ describe("buildSnapshotFromSessionEvents", () => {
|
|
|
2824
2882
|
});
|
|
2825
2883
|
});
|
|
2826
2884
|
|
|
2827
|
-
describe("
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2885
|
+
describe("buildSnapshotThroughTurn", () => {
|
|
2886
|
+
/** Linear session t1 -> t2 -> t3, oldest-first. */
|
|
2887
|
+
function linearTurns(): TurnFixture[] {
|
|
2888
|
+
return [
|
|
2889
|
+
mockTurn({
|
|
2890
|
+
id: "t1",
|
|
2891
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
2892
|
+
previousTurnId: null,
|
|
2893
|
+
input: [{ type: "user.message", content: "first" }],
|
|
2894
|
+
events: [
|
|
2895
|
+
modelMessage({ id: "m1", threadId: ROOT_THREAD_ID, content: "reply 1" }),
|
|
2835
2896
|
],
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2897
|
+
}),
|
|
2898
|
+
mockTurn({
|
|
2899
|
+
id: "t2",
|
|
2900
|
+
createdAt: "2026-01-01T00:01:00.000Z",
|
|
2901
|
+
previousTurnId: "t1",
|
|
2902
|
+
input: [{ type: "user.message", content: "second" }],
|
|
2903
|
+
events: [
|
|
2904
|
+
modelMessage({ id: "m2", threadId: ROOT_THREAD_ID, content: "reply 2" }),
|
|
2843
2905
|
],
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2906
|
+
}),
|
|
2907
|
+
mockTurn({
|
|
2908
|
+
id: "t3",
|
|
2909
|
+
createdAt: "2026-01-01T00:02:00.000Z",
|
|
2910
|
+
previousTurnId: "t2",
|
|
2911
|
+
input: [{ type: "user.message", content: "third" }],
|
|
2912
|
+
events: [
|
|
2913
|
+
modelMessage({ id: "m3", threadId: ROOT_THREAD_ID, content: "reply 3" }),
|
|
2851
2914
|
],
|
|
2852
|
-
|
|
2915
|
+
}),
|
|
2916
|
+
];
|
|
2917
|
+
}
|
|
2853
2918
|
|
|
2854
|
-
|
|
2855
|
-
const server = mockServerWithTurns(
|
|
2856
|
-
const snapshot = await
|
|
2919
|
+
it("rewinds to the anchor's ancestor chain, inclusive", async () => {
|
|
2920
|
+
const server = mockServerWithTurns(linearTurns());
|
|
2921
|
+
const snapshot = await buildSnapshotThroughTurn(server, SESSION_ID, "t2");
|
|
2857
2922
|
|
|
2858
2923
|
expect(snapshot.turns.map((turn) => turn.id)).toEqual(["t1", "t2"]);
|
|
2859
|
-
|
|
2860
|
-
expect(messages.map((message) => message.id)).toEqual([
|
|
2924
|
+
expect(projectSessionMessages(snapshot).map((message) => message.id)).toEqual([
|
|
2861
2925
|
"t1-user",
|
|
2862
2926
|
"t1-assistant",
|
|
2863
2927
|
"t2-user",
|
|
@@ -2865,12 +2929,116 @@ describe("buildSnapshotBeforeTurnIndex", () => {
|
|
|
2865
2929
|
]);
|
|
2866
2930
|
});
|
|
2867
2931
|
|
|
2868
|
-
it("returns an empty snapshot
|
|
2869
|
-
const server = mockServerWithTurns(
|
|
2870
|
-
|
|
2871
|
-
]);
|
|
2872
|
-
const snapshot = await buildSnapshotBeforeTurnIndex(server, SESSION_ID, 0);
|
|
2932
|
+
it("returns an empty snapshot for a null anchor (branching from a root turn)", async () => {
|
|
2933
|
+
const server = mockServerWithTurns(linearTurns());
|
|
2934
|
+
const snapshot = await buildSnapshotThroughTurn(server, SESSION_ID, null);
|
|
2873
2935
|
expect(snapshot.turns).toHaveLength(0);
|
|
2874
2936
|
});
|
|
2937
|
+
|
|
2938
|
+
it("ignores listTurns page order", async () => {
|
|
2939
|
+
const asc = linearTurns();
|
|
2940
|
+
const ascSnapshot = await buildSnapshotThroughTurn(
|
|
2941
|
+
mockServerWithTurns(asc),
|
|
2942
|
+
SESSION_ID,
|
|
2943
|
+
"t2",
|
|
2944
|
+
);
|
|
2945
|
+
const descSnapshot = await buildSnapshotThroughTurn(
|
|
2946
|
+
mockServerWithTurns([...asc].reverse()),
|
|
2947
|
+
SESSION_ID,
|
|
2948
|
+
"t2",
|
|
2949
|
+
);
|
|
2950
|
+
|
|
2951
|
+
expect(descSnapshot.turns.map((turn) => turn.id)).toEqual(
|
|
2952
|
+
ascSnapshot.turns.map((turn) => turn.id),
|
|
2953
|
+
);
|
|
2954
|
+
expect(descSnapshot.turns.map((turn) => turn.id)).toEqual(["t1", "t2"]);
|
|
2955
|
+
});
|
|
2956
|
+
|
|
2957
|
+
it("drops sibling turns left behind by an earlier rerun", async () => {
|
|
2958
|
+
// m2/m3 were rerun once already: t2/t3 are orphans, t2p/t3p are live.
|
|
2959
|
+
const [t1, t2, t3] = linearTurns();
|
|
2960
|
+
const t2p = mockTurn({
|
|
2961
|
+
id: "t2p",
|
|
2962
|
+
createdAt: "2026-01-01T00:03:00.000Z",
|
|
2963
|
+
previousTurnId: "t1",
|
|
2964
|
+
input: [{ type: "user.message", content: "second again" }],
|
|
2965
|
+
events: [
|
|
2966
|
+
modelMessage({ id: "m2p", threadId: ROOT_THREAD_ID, content: "reply 2p" }),
|
|
2967
|
+
],
|
|
2968
|
+
});
|
|
2969
|
+
const t3p = mockTurn({
|
|
2970
|
+
id: "t3p",
|
|
2971
|
+
createdAt: "2026-01-01T00:04:00.000Z",
|
|
2972
|
+
previousTurnId: "t2p",
|
|
2973
|
+
input: [{ type: "user.message", content: "third again" }],
|
|
2974
|
+
events: [
|
|
2975
|
+
modelMessage({ id: "m3p", threadId: ROOT_THREAD_ID, content: "reply 3p" }),
|
|
2976
|
+
],
|
|
2977
|
+
});
|
|
2978
|
+
const server = mockServerWithTurns([t1!, t2!, t3!, t2p, t3p]);
|
|
2979
|
+
|
|
2980
|
+
// Rerunning the middle live turn rewinds to its parent, not to the
|
|
2981
|
+
// chronologically preceding turn (t3), whose chain still holds t2/t3.
|
|
2982
|
+
const previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
2983
|
+
server,
|
|
2984
|
+
SESSION_ID,
|
|
2985
|
+
"t2p",
|
|
2986
|
+
);
|
|
2987
|
+
expect(previousTurnId).toBe("t1");
|
|
2988
|
+
|
|
2989
|
+
const snapshot = await buildSnapshotThroughTurn(server, SESSION_ID, previousTurnId);
|
|
2990
|
+
expect(snapshot.turns.map((turn) => turn.id)).toEqual(["t1"]);
|
|
2991
|
+
|
|
2992
|
+
// The orphan chain is still reachable, so the assertion above is not
|
|
2993
|
+
// passing by accident.
|
|
2994
|
+
const orphanSnapshot = await buildSnapshotThroughTurn(server, SESSION_ID, "t3");
|
|
2995
|
+
expect(orphanSnapshot.turns.map((turn) => turn.id)).toEqual(["t1", "t2", "t3"]);
|
|
2996
|
+
});
|
|
2997
|
+
});
|
|
2998
|
+
|
|
2999
|
+
describe("resolveGatewayBranchPreviousTurnIdForTurn", () => {
|
|
3000
|
+
it("uses the turn parent for subsequent turns and none for roots (ASC listTurns)", async () => {
|
|
3001
|
+
const t1 = mockTurn({
|
|
3002
|
+
id: "t1",
|
|
3003
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
3004
|
+
previousTurnId: null,
|
|
3005
|
+
});
|
|
3006
|
+
const t2 = mockTurn({
|
|
3007
|
+
id: "t2",
|
|
3008
|
+
createdAt: "2026-01-01T00:01:00.000Z",
|
|
3009
|
+
previousTurnId: "t1",
|
|
3010
|
+
});
|
|
3011
|
+
const t3 = mockTurn({
|
|
3012
|
+
id: "t3",
|
|
3013
|
+
createdAt: "2026-01-01T00:02:00.000Z",
|
|
3014
|
+
previousTurnId: "t2",
|
|
3015
|
+
});
|
|
3016
|
+
const server = mockServerWithTurns([t1, t2, t3]);
|
|
3017
|
+
|
|
3018
|
+
await expect(
|
|
3019
|
+
resolveGatewayBranchPreviousTurnIdForTurn(server, SESSION_ID, "t1"),
|
|
3020
|
+
).resolves.toBe("none");
|
|
3021
|
+
await expect(
|
|
3022
|
+
resolveGatewayBranchPreviousTurnIdForTurn(server, SESSION_ID, "t3"),
|
|
3023
|
+
).resolves.toBe("t2");
|
|
3024
|
+
});
|
|
3025
|
+
|
|
3026
|
+
it("uses the turn parent when listTurns is newest-first", async () => {
|
|
3027
|
+
const t1 = mockTurn({
|
|
3028
|
+
id: "t1",
|
|
3029
|
+
createdAt: "2026-01-01T00:00:00.000Z",
|
|
3030
|
+
previousTurnId: null,
|
|
3031
|
+
});
|
|
3032
|
+
const t2 = mockTurn({
|
|
3033
|
+
id: "t2",
|
|
3034
|
+
createdAt: "2026-01-01T00:01:00.000Z",
|
|
3035
|
+
previousTurnId: "t1",
|
|
3036
|
+
});
|
|
3037
|
+
const server = mockServerWithTurns([t2, t1]);
|
|
3038
|
+
|
|
3039
|
+
await expect(
|
|
3040
|
+
resolveGatewayBranchPreviousTurnIdForTurn(server, SESSION_ID, "t2"),
|
|
3041
|
+
).resolves.toBe("t1");
|
|
3042
|
+
});
|
|
2875
3043
|
});
|
|
2876
3044
|
|