@truefoundry/assistant-ui-runtime 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +22 -17
- package/dist/chunk-CXBZ6WLZ.js +636 -0
- package/dist/chunk-CXBZ6WLZ.js.map +1 -0
- package/dist/index.d.ts +20 -24
- package/dist/index.js +269 -166
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +82 -39
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +3 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-BfiFf8O1.d.ts → types-B_z-FsDS.d.ts} +208 -10
- package/package.json +1 -1
- package/src/convertTurnMessages.ts +4 -0
- package/src/{private → draft}/agentSpec.ts +14 -17
- package/src/{private → draft}/draftSessionBridge.ts +1 -2
- package/src/{private → draft}/truefoundryDraftThreadListAdapter.test.ts +1 -1
- package/src/{private → draft}/truefoundryDraftThreadListAdapter.ts +6 -2
- package/src/{private → draft}/useDraftAgentSpec.ts +16 -5
- package/src/draftAgentConfig.test.ts +2 -1
- package/src/harness.temp.ts +85 -0
- package/src/index.ts +43 -7
- package/src/plugins/truefoundry-agent-server-adapter/README.md +83 -44
- package/src/plugins/truefoundry-agent-server-adapter/chatServer.ts +365 -0
- package/src/plugins/truefoundry-agent-server-adapter/cp.test.ts +444 -0
- package/src/plugins/truefoundry-agent-server-adapter/cp.ts +482 -0
- package/src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts +94 -0
- package/src/plugins/truefoundry-agent-server-adapter/guards.ts +1 -1
- package/src/plugins/truefoundry-agent-server-adapter/index.ts +20 -351
- package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.test.ts +85 -0
- package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.ts +84 -0
- package/src/plugins/truefoundry-agent-server-adapter/types.ts +7 -5
- package/src/server/index.ts +29 -0
- package/src/server/types.ts +264 -12
- package/src/streamTurn.test.ts +27 -27
- package/src/streamTurn.ts +2 -2
- package/src/truefoundryExtras.ts +4 -1
- package/src/truefoundryOwnedSessionsThreadListAdapter.ts +5 -2
- package/src/truefoundryThreadListAdapter.test.ts +22 -0
- package/src/truefoundryThreadListAdapter.ts +4 -1
- package/src/types.ts +1 -2
- package/src/useTrueFoundryAgentMessages.test.tsx +262 -2
- package/src/useTrueFoundryAgentMessages.ts +284 -176
- package/src/useTrueFoundryAgentRuntime.ts +31 -21
- package/dist/chunk-Q2SHKMLM.js +0 -270
- package/dist/chunk-Q2SHKMLM.js.map +0 -1
- /package/src/{private → draft}/useDraftAgentSpec.test.tsx +0 -0
package/src/server/types.ts
CHANGED
|
@@ -10,8 +10,7 @@ import type {
|
|
|
10
10
|
ActionRequiredEvent,
|
|
11
11
|
SessionEventItem,
|
|
12
12
|
TurnEvent,
|
|
13
|
-
TurnStreamData
|
|
14
|
-
TurnStreamingEvent,
|
|
13
|
+
TurnStreamData
|
|
15
14
|
} from "./events.js";
|
|
16
15
|
|
|
17
16
|
// ---------------------------------------------------------------------------
|
|
@@ -72,7 +71,7 @@ export type SkillMount = object;
|
|
|
72
71
|
export type McpServerMount = object;
|
|
73
72
|
|
|
74
73
|
// ---------------------------------------------------------------------------
|
|
75
|
-
// AgentSpec — model
|
|
74
|
+
// AgentSpec — model / skills / mcpServers are type params; host widens the rest
|
|
76
75
|
// ---------------------------------------------------------------------------
|
|
77
76
|
|
|
78
77
|
export interface ModelParams {
|
|
@@ -87,17 +86,19 @@ export interface Model {
|
|
|
87
86
|
|
|
88
87
|
/**
|
|
89
88
|
* SDK-owned agent definition — fields the FE reads/writes.
|
|
90
|
-
* Host
|
|
89
|
+
* Host widens `model` / `skills` / `mcpServers` via type params, and adds
|
|
90
|
+
* extra fields via `TSpec extends AgentSpec<...>`.
|
|
91
91
|
*/
|
|
92
|
-
export interface AgentSpec
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
export interface AgentSpec<
|
|
93
|
+
TModel extends Model = Model,
|
|
94
|
+
TSkill extends SkillMount = SkillMount,
|
|
95
|
+
TMcp extends McpServerMount = McpServerMount,
|
|
96
|
+
> {
|
|
97
|
+
model: TModel;
|
|
98
|
+
skills?: TSkill[];
|
|
99
|
+
mcpServers?: TMcp[];
|
|
96
100
|
instructions?: string;
|
|
97
|
-
messages?: unknown[];
|
|
98
101
|
variables?: Record<string, string>;
|
|
99
|
-
responseFormat?: unknown;
|
|
100
|
-
config?: unknown;
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
// ---------------------------------------------------------------------------
|
|
@@ -248,7 +249,7 @@ export interface AgentChatServer<
|
|
|
248
249
|
getSession(req: { sessionId: string }): Promise<TSession>;
|
|
249
250
|
updateSession(req: TUpdate): Promise<TSession>;
|
|
250
251
|
|
|
251
|
-
|
|
252
|
+
createTurn(req: {
|
|
252
253
|
sessionId: string;
|
|
253
254
|
input?: TurnInputItem[];
|
|
254
255
|
previousTurnId?: PreviousTurnIdInput;
|
|
@@ -317,3 +318,254 @@ export interface AgentBuilderServer<
|
|
|
317
318
|
}): Promise<TSave>;
|
|
318
319
|
deleteAgent?(req: { agentName: string }): Promise<void>;
|
|
319
320
|
}
|
|
321
|
+
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// Catalog management — FE-minimal settings DTOs (host extends via generics)
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Provider type id. Reserved literal: `"custom"` for user-defined providers;
|
|
328
|
+
* any other string is a builtin (e.g. `"openai"`, `"anthropic"`).
|
|
329
|
+
*
|
|
330
|
+
* Note: `string | "custom"` is useless in TypeScript (`"custom"` ⊆ `string`),
|
|
331
|
+
* so this stays `string` and `"custom"` is a documented convention.
|
|
332
|
+
*/
|
|
333
|
+
export type ProviderType = string;
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Model row — form "Model ID" + "Display name".
|
|
337
|
+
* Host extends for properties, etc.
|
|
338
|
+
*/
|
|
339
|
+
export interface ModelEntry {
|
|
340
|
+
id: string;
|
|
341
|
+
name: string;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Write config for create/update (custom form + catalog "Save key").
|
|
346
|
+
* Host extends. `baseUrl` present iff `type === "custom"`.
|
|
347
|
+
*/
|
|
348
|
+
export interface ModelProviderConfigBase<TModel extends ModelEntry = ModelEntry> {
|
|
349
|
+
type: ProviderType;
|
|
350
|
+
name: string;
|
|
351
|
+
/** Present iff `type === "custom"`. */
|
|
352
|
+
baseUrl?: string;
|
|
353
|
+
apiKey: string;
|
|
354
|
+
models: TModel[];
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Configured provider card (list/read). No raw `apiKey`.
|
|
359
|
+
* Host extends for apiKeySet, timestamps, etc.
|
|
360
|
+
*/
|
|
361
|
+
export interface ModelProviderBase<TModel extends ModelEntry = ModelEntry> {
|
|
362
|
+
id: string;
|
|
363
|
+
type: ProviderType;
|
|
364
|
+
name: string;
|
|
365
|
+
/** Present iff `type === "custom"`. */
|
|
366
|
+
baseUrl?: string;
|
|
367
|
+
models: TModel[];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Discovery-only catalog provider (AVAILABLE list).
|
|
372
|
+
* `type` must not be `"custom"` — custom providers use the custom form.
|
|
373
|
+
* Host extends for richer model rows.
|
|
374
|
+
*/
|
|
375
|
+
export interface ModelProviderCatalogEntry<TModel extends ModelEntry = ModelEntry> {
|
|
376
|
+
type: ProviderType;
|
|
377
|
+
name: string;
|
|
378
|
+
models: TModel[];
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Create — no `id`; server assigns it. Catalog path = entry + apiKey. */
|
|
382
|
+
export type CreateModelProviderRequest<TModel extends ModelEntry = ModelEntry> =
|
|
383
|
+
ModelProviderConfigBase<TModel>;
|
|
384
|
+
|
|
385
|
+
/** Update — `id` required. */
|
|
386
|
+
export type UpdateModelProviderRequest<TModel extends ModelEntry = ModelEntry> =
|
|
387
|
+
ModelProviderConfigBase<TModel> & { id: string };
|
|
388
|
+
|
|
389
|
+
export interface ModelCatalogServer<
|
|
390
|
+
TModel extends ModelEntry = ModelEntry,
|
|
391
|
+
TProvider extends ModelProviderBase<TModel> = ModelProviderBase<TModel>,
|
|
392
|
+
TCatalogProvider extends ModelProviderCatalogEntry<TModel> = ModelProviderCatalogEntry<TModel>,
|
|
393
|
+
TCreate extends CreateModelProviderRequest<TModel> = CreateModelProviderRequest<TModel>,
|
|
394
|
+
TUpdate extends UpdateModelProviderRequest<TModel> = UpdateModelProviderRequest<TModel>,
|
|
395
|
+
> {
|
|
396
|
+
getModelProviderCatalog(): Promise<TCatalogProvider[]>;
|
|
397
|
+
listModelProviders(): Promise<TProvider[]>;
|
|
398
|
+
createModelProvider(req: TCreate): Promise<TProvider>;
|
|
399
|
+
/** Full replace update keyed by provider `id`. */
|
|
400
|
+
updateModelProvider(req: TUpdate): Promise<TProvider>;
|
|
401
|
+
deleteModelProvider?(req: { id: string }): Promise<void>;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/** Tool row on a connector detail. Host extends for schemas, etc. */
|
|
405
|
+
export interface ToolBase {
|
|
406
|
+
id: string;
|
|
407
|
+
name: string;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** Strict auth type id. Hosts widen branches via intersection + re-union. */
|
|
411
|
+
export type ConnectorAuthType = "oauth" | "apiKey" | "none";
|
|
412
|
+
|
|
413
|
+
// Write (create/update) — export branches so hosts can intersect extras
|
|
414
|
+
export type ConnectorAuthOAuth = { type: "oauth"; authUrl?: string };
|
|
415
|
+
export type ConnectorAuthApiKey = {
|
|
416
|
+
type: "apiKey";
|
|
417
|
+
apiKey?: string;
|
|
418
|
+
headerName?: string;
|
|
419
|
+
};
|
|
420
|
+
export type ConnectorAuthNone = { type: "none" };
|
|
421
|
+
export type ConnectorAuth =
|
|
422
|
+
| ConnectorAuthOAuth
|
|
423
|
+
| ConnectorAuthApiKey
|
|
424
|
+
| ConnectorAuthNone;
|
|
425
|
+
|
|
426
|
+
// Public (list/detail) — no secrets; oauth requires authUrl
|
|
427
|
+
export type ConnectorAuthPublicOAuth = { type: "oauth"; authUrl: string };
|
|
428
|
+
export type ConnectorAuthPublicApiKey = {
|
|
429
|
+
type: "apiKey";
|
|
430
|
+
headerName?: string;
|
|
431
|
+
};
|
|
432
|
+
export type ConnectorAuthPublicNone = { type: "none" };
|
|
433
|
+
export type ConnectorAuthPublic =
|
|
434
|
+
| ConnectorAuthPublicOAuth
|
|
435
|
+
| ConnectorAuthPublicApiKey
|
|
436
|
+
| ConnectorAuthPublicNone;
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* MCP / connector create-edit config. Host extends for extra fields, etc.
|
|
440
|
+
*/
|
|
441
|
+
export interface ConnectorConfigBase<
|
|
442
|
+
TAuth extends ConnectorAuth = ConnectorAuth,
|
|
443
|
+
> {
|
|
444
|
+
name: string;
|
|
445
|
+
url: string;
|
|
446
|
+
auth: TAuth;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Connected connector row (settings/connectors). No raw `apiKey`.
|
|
451
|
+
* Host extends.
|
|
452
|
+
*/
|
|
453
|
+
export interface ConnectorBase<
|
|
454
|
+
TTool extends ToolBase = ToolBase,
|
|
455
|
+
TAuth extends ConnectorAuthPublic = ConnectorAuthPublic,
|
|
456
|
+
> {
|
|
457
|
+
id: string;
|
|
458
|
+
name: string;
|
|
459
|
+
description: string;
|
|
460
|
+
url: string;
|
|
461
|
+
auth: TAuth;
|
|
462
|
+
/** When true, UI should not show Disconnect. */
|
|
463
|
+
requiresAuth: boolean;
|
|
464
|
+
authenticated: boolean;
|
|
465
|
+
tools: TTool[];
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/** Discovery catalog entry for "+ Add MCP server". Host extends. */
|
|
469
|
+
export interface ConnectorCatalogEntry<
|
|
470
|
+
TAuth extends ConnectorAuthPublic = ConnectorAuthPublic,
|
|
471
|
+
> {
|
|
472
|
+
id: string;
|
|
473
|
+
name: string;
|
|
474
|
+
description?: string;
|
|
475
|
+
url: string;
|
|
476
|
+
auth: TAuth;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/** Create connector — no `id`; server assigns it. Host extends. */
|
|
480
|
+
export type CreateConnectorRequest<TAuth extends ConnectorAuth = ConnectorAuth> =
|
|
481
|
+
ConnectorConfigBase<TAuth>;
|
|
482
|
+
|
|
483
|
+
/** Update connector — `id` required. Host extends. */
|
|
484
|
+
export type UpdateConnectorRequest<TAuth extends ConnectorAuth = ConnectorAuth> =
|
|
485
|
+
ConnectorConfigBase<TAuth> & { id: string };
|
|
486
|
+
|
|
487
|
+
export interface ConnectorCatalogServer<
|
|
488
|
+
TTool extends ToolBase = ToolBase,
|
|
489
|
+
TAuthWrite extends ConnectorAuth = ConnectorAuth,
|
|
490
|
+
TAuthPublic extends ConnectorAuthPublic = ConnectorAuthPublic,
|
|
491
|
+
TConnector extends ConnectorBase<TTool, TAuthPublic> = ConnectorBase<
|
|
492
|
+
TTool,
|
|
493
|
+
TAuthPublic
|
|
494
|
+
>,
|
|
495
|
+
TCatalogEntry extends ConnectorCatalogEntry<TAuthPublic> =
|
|
496
|
+
ConnectorCatalogEntry<TAuthPublic>,
|
|
497
|
+
TCreate extends CreateConnectorRequest<TAuthWrite> =
|
|
498
|
+
CreateConnectorRequest<TAuthWrite>,
|
|
499
|
+
TUpdate extends UpdateConnectorRequest<TAuthWrite> =
|
|
500
|
+
UpdateConnectorRequest<TAuthWrite>,
|
|
501
|
+
> {
|
|
502
|
+
getConnectorCatalog(): Promise<TCatalogEntry[]>;
|
|
503
|
+
listConnectors(req?: { query?: string }): Promise<TConnector[]>;
|
|
504
|
+
createConnector(req: TCreate): Promise<TConnector>;
|
|
505
|
+
/** Full replace update keyed by connector `id`. */
|
|
506
|
+
updateConnector(req: TUpdate): Promise<TConnector>;
|
|
507
|
+
/**
|
|
508
|
+
* Start connector auth (e.g. OAuth).
|
|
509
|
+
* For oauth, the returned connector's `auth.authUrl` is the authorize URL.
|
|
510
|
+
*/
|
|
511
|
+
authenticateConnector(req: { id: string }): Promise<TConnector>;
|
|
512
|
+
/** Clear connector auth. */
|
|
513
|
+
disconnectConnector(req: { id: string }): Promise<TConnector>;
|
|
514
|
+
deleteConnector?(req: { id: string }): Promise<void>;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ---------------------------------------------------------------------------
|
|
518
|
+
// Skills catalog — FE-minimal settings DTOs (host extends via generics)
|
|
519
|
+
// ---------------------------------------------------------------------------
|
|
520
|
+
|
|
521
|
+
/** Skill row shown in settings/skills (list + delete). Host extends for fqn, etc. */
|
|
522
|
+
export interface SkillBase {
|
|
523
|
+
id: string;
|
|
524
|
+
name: string;
|
|
525
|
+
description: string;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/** Create-skill request. Host extends for branch, auth, etc. */
|
|
529
|
+
export interface CreateSkillRequest {
|
|
530
|
+
repo: string;
|
|
531
|
+
directory: string;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export interface SkillCatalogServer<
|
|
535
|
+
TSkill extends SkillBase = SkillBase,
|
|
536
|
+
TCreate extends CreateSkillRequest = CreateSkillRequest,
|
|
537
|
+
> {
|
|
538
|
+
listSkills(req?: { query?: string }): Promise<TSkill[]>;
|
|
539
|
+
createSkill(req: TCreate): Promise<TSkill>;
|
|
540
|
+
deleteSkill?(req: { id: string }): Promise<void>;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* Settings management aggregate — modelCatalog + connectorCatalog + optional skillCatalog.
|
|
545
|
+
* Hosts may pass the whole object to an app shell, or a focused sub-port to a page.
|
|
546
|
+
*/
|
|
547
|
+
export interface CatalogServer<
|
|
548
|
+
TModelCatalog extends ModelCatalogServer = ModelCatalogServer,
|
|
549
|
+
TConnectorCatalog extends ConnectorCatalogServer = ConnectorCatalogServer,
|
|
550
|
+
TSkillCatalog extends SkillCatalogServer = SkillCatalogServer,
|
|
551
|
+
> {
|
|
552
|
+
modelCatalog: TModelCatalog;
|
|
553
|
+
connectorCatalog: TConnectorCatalog;
|
|
554
|
+
/** Optional — omit when the host has no skills settings surface. */
|
|
555
|
+
skillCatalog?: TSkillCatalog;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Composed host port: chat + builder + optional settings catalog.
|
|
560
|
+
* Agent-ui's `AgentUIServer` mirrors this shape; named differently here to
|
|
561
|
+
* avoid colliding with that package's local type name.
|
|
562
|
+
*
|
|
563
|
+
* `catalog` is optional — if the host passes it, settings UI can call
|
|
564
|
+
* `useCatalogServer()` / show modelCatalog, connectorCatalog, and skillCatalog;
|
|
565
|
+
* if omitted, those surfaces stay hidden.
|
|
566
|
+
*/
|
|
567
|
+
export type AgentUIServerPort<
|
|
568
|
+
TChat extends AgentChatServer = AgentChatServer,
|
|
569
|
+
TBuilder extends AgentBuilderServer = AgentBuilderServer,
|
|
570
|
+
TCatalog extends CatalogServer = CatalogServer,
|
|
571
|
+
> = TChat & TBuilder & { catalog?: TCatalog };
|
package/src/streamTurn.test.ts
CHANGED
|
@@ -33,7 +33,7 @@ describe("streamTurn", () => {
|
|
|
33
33
|
describe("streamTurnContent", () => {
|
|
34
34
|
it("prepares a user turn and yields folded stream updates", async () => {
|
|
35
35
|
const foldState = new PeerThreadFoldState();
|
|
36
|
-
const
|
|
36
|
+
const createTurn = vi.fn(async function* () {
|
|
37
37
|
yield streamData(1, {
|
|
38
38
|
type: "model.message",
|
|
39
39
|
createdAt,
|
|
@@ -43,7 +43,7 @@ describe("streamTurn", () => {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
const server = mockServer({
|
|
46
|
-
|
|
46
|
+
createTurn,
|
|
47
47
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -57,7 +57,7 @@ describe("streamTurn", () => {
|
|
|
57
57
|
),
|
|
58
58
|
);
|
|
59
59
|
|
|
60
|
-
expect(
|
|
60
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
61
61
|
sessionId: SESSION_ID,
|
|
62
62
|
input: [{ type: "user.message", content: "hello" }],
|
|
63
63
|
previousTurnId: "auto",
|
|
@@ -68,7 +68,7 @@ describe("streamTurn", () => {
|
|
|
68
68
|
]);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it("passes required-action inputs through
|
|
71
|
+
it("passes required-action inputs through createTurn", async () => {
|
|
72
72
|
const inputs = [
|
|
73
73
|
{
|
|
74
74
|
type: "user.tool_approval" as const,
|
|
@@ -83,9 +83,9 @@ describe("streamTurn", () => {
|
|
|
83
83
|
content: "A",
|
|
84
84
|
},
|
|
85
85
|
];
|
|
86
|
-
const
|
|
86
|
+
const createTurn = vi.fn(async function* () {});
|
|
87
87
|
const server = mockServer({
|
|
88
|
-
|
|
88
|
+
createTurn,
|
|
89
89
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -99,7 +99,7 @@ describe("streamTurn", () => {
|
|
|
99
99
|
),
|
|
100
100
|
);
|
|
101
101
|
|
|
102
|
-
expect(
|
|
102
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
103
103
|
sessionId: SESSION_ID,
|
|
104
104
|
input: inputs,
|
|
105
105
|
previousTurnId: "auto",
|
|
@@ -108,9 +108,9 @@ describe("streamTurn", () => {
|
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it("uses empty input when resuming after MCP auth", async () => {
|
|
111
|
-
const
|
|
111
|
+
const createTurn = vi.fn(async function* () {});
|
|
112
112
|
const server = mockServer({
|
|
113
|
-
|
|
113
|
+
createTurn,
|
|
114
114
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
115
115
|
});
|
|
116
116
|
|
|
@@ -124,7 +124,7 @@ describe("streamTurn", () => {
|
|
|
124
124
|
),
|
|
125
125
|
);
|
|
126
126
|
|
|
127
|
-
expect(
|
|
127
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
128
128
|
sessionId: SESSION_ID,
|
|
129
129
|
input: [],
|
|
130
130
|
previousTurnId: "auto",
|
|
@@ -133,9 +133,9 @@ describe("streamTurn", () => {
|
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
it("forwards an explicit previousTurnId when branching", async () => {
|
|
136
|
-
const
|
|
136
|
+
const createTurn = vi.fn(async function* () {});
|
|
137
137
|
const server = mockServer({
|
|
138
|
-
|
|
138
|
+
createTurn,
|
|
139
139
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
140
140
|
});
|
|
141
141
|
|
|
@@ -149,7 +149,7 @@ describe("streamTurn", () => {
|
|
|
149
149
|
),
|
|
150
150
|
);
|
|
151
151
|
|
|
152
|
-
expect(
|
|
152
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
153
153
|
sessionId: SESSION_ID,
|
|
154
154
|
input: [{ type: "user.message", content: "edited" }],
|
|
155
155
|
previousTurnId: "turn-a",
|
|
@@ -158,9 +158,9 @@ describe("streamTurn", () => {
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
it("forwards previousTurnId \"none\" when branching from root", async () => {
|
|
161
|
-
const
|
|
161
|
+
const createTurn = vi.fn(async function* () {});
|
|
162
162
|
const server = mockServer({
|
|
163
|
-
|
|
163
|
+
createTurn,
|
|
164
164
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
165
165
|
});
|
|
166
166
|
|
|
@@ -174,7 +174,7 @@ describe("streamTurn", () => {
|
|
|
174
174
|
),
|
|
175
175
|
);
|
|
176
176
|
|
|
177
|
-
expect(
|
|
177
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
178
178
|
sessionId: SESSION_ID,
|
|
179
179
|
input: [{ type: "user.message", content: "first" }],
|
|
180
180
|
previousTurnId: "none",
|
|
@@ -183,9 +183,9 @@ describe("streamTurn", () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it("returns early and cancels the session when already aborted", async () => {
|
|
186
|
-
const
|
|
186
|
+
const createTurn = vi.fn(async function* () {});
|
|
187
187
|
const cancelSession = vi.fn().mockResolvedValue(undefined);
|
|
188
|
-
const server = mockServer({
|
|
188
|
+
const server = mockServer({ createTurn, cancelSession });
|
|
189
189
|
const abortController = new AbortController();
|
|
190
190
|
abortController.abort();
|
|
191
191
|
|
|
@@ -200,14 +200,14 @@ describe("streamTurn", () => {
|
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
expect(cancelSession).toHaveBeenCalledWith({ sessionId: SESSION_ID });
|
|
203
|
-
expect(
|
|
203
|
+
expect(createTurn).not.toHaveBeenCalled();
|
|
204
204
|
expect(updates).toEqual([]);
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
-
it("forwards headers to
|
|
208
|
-
const
|
|
207
|
+
it("forwards headers to createTurn", async () => {
|
|
208
|
+
const createTurn = vi.fn(async function* () {});
|
|
209
209
|
const server = mockServer({
|
|
210
|
-
|
|
210
|
+
createTurn,
|
|
211
211
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
212
212
|
});
|
|
213
213
|
const abortSignal = new AbortController().signal;
|
|
@@ -227,7 +227,7 @@ describe("streamTurn", () => {
|
|
|
227
227
|
),
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
expect(
|
|
230
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
231
231
|
sessionId: SESSION_ID,
|
|
232
232
|
input: [{ type: "user.message", content: "hello" }],
|
|
233
233
|
previousTurnId: "auto",
|
|
@@ -240,7 +240,7 @@ describe("streamTurn", () => {
|
|
|
240
240
|
|
|
241
241
|
it("notifies gateway turn id when turn.done errors with no content yields", async () => {
|
|
242
242
|
const gatewayTurnId = "01ky6mqzmczwt6ssyd5r02gjjc";
|
|
243
|
-
const
|
|
243
|
+
const createTurn = vi.fn(async function* () {
|
|
244
244
|
yield streamData(1, {
|
|
245
245
|
type: "turn.created",
|
|
246
246
|
createdAt,
|
|
@@ -261,7 +261,7 @@ describe("streamTurn", () => {
|
|
|
261
261
|
});
|
|
262
262
|
});
|
|
263
263
|
const server = mockServer({
|
|
264
|
-
|
|
264
|
+
createTurn,
|
|
265
265
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
266
266
|
});
|
|
267
267
|
const onTurnIdAvailable = vi.fn();
|
|
@@ -285,7 +285,7 @@ describe("streamTurn", () => {
|
|
|
285
285
|
});
|
|
286
286
|
|
|
287
287
|
it("does not notify when an error stream never emits turn.created", async () => {
|
|
288
|
-
const
|
|
288
|
+
const createTurn = vi.fn(async function* () {
|
|
289
289
|
yield streamData(1, {
|
|
290
290
|
type: "turn.done",
|
|
291
291
|
createdAt,
|
|
@@ -298,7 +298,7 @@ describe("streamTurn", () => {
|
|
|
298
298
|
});
|
|
299
299
|
});
|
|
300
300
|
const server = mockServer({
|
|
301
|
-
|
|
301
|
+
createTurn,
|
|
302
302
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
303
303
|
});
|
|
304
304
|
const onTurnIdAvailable = vi.fn();
|
package/src/streamTurn.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type StreamTurnOptions = {
|
|
|
18
18
|
resumeMcpAuth?: boolean;
|
|
19
19
|
inputs?: RequiredActionInput[];
|
|
20
20
|
/**
|
|
21
|
-
* Branch anchor for
|
|
21
|
+
* Branch anchor for createTurn. Omit for `"auto"`. Pass `"none"` for a fresh
|
|
22
22
|
* root turn.
|
|
23
23
|
*/
|
|
24
24
|
previousTurnId?: PreviousTurnIdInput;
|
|
@@ -79,7 +79,7 @@ export async function* streamTurnContent(
|
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
const stream: AsyncIterable<TurnStreamData> = server.
|
|
82
|
+
const stream: AsyncIterable<TurnStreamData> = server.createTurn({
|
|
83
83
|
sessionId,
|
|
84
84
|
input: buildTurnInput(options),
|
|
85
85
|
previousTurnId: options.previousTurnId ?? "auto",
|
package/src/truefoundryExtras.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createRuntimeExtras } from "@assistant-ui/core/internal";
|
|
2
2
|
import type { McpAuthRequiredEvent } from "./server/index.js";
|
|
3
3
|
|
|
4
|
-
import type { AgentSpec
|
|
4
|
+
import type { AgentSpec } from "./server/types.js";
|
|
5
|
+
import type { AgentSpecUpdate } from "./draft/agentSpec.js";
|
|
5
6
|
import type { PendingApproval, PendingToolResponse } from "./collectPending.js";
|
|
6
7
|
import type { RespondToToolApprovalOptions } from "./toolApproval.js";
|
|
7
8
|
import type { RespondToToolResponseOptions } from "./toolResponse.js";
|
|
@@ -11,6 +12,7 @@ export type { PendingApproval, PendingToolResponse };
|
|
|
11
12
|
export type TrueFoundryDraftRuntimeExtras = {
|
|
12
13
|
agentSpec: AgentSpec | null;
|
|
13
14
|
draftSessionId: string | undefined;
|
|
15
|
+
isSpecLoading: boolean;
|
|
14
16
|
isSpecSyncing: boolean;
|
|
15
17
|
specError: unknown | null;
|
|
16
18
|
updateAgentSpec: (update: AgentSpecUpdate) => void;
|
|
@@ -41,6 +43,7 @@ export const trueFoundryExtras = createRuntimeExtras<TrueFoundryRuntimeExtras>(
|
|
|
41
43
|
export const EMPTY_DRAFT_EXTRAS: TrueFoundryDraftRuntimeExtras = {
|
|
42
44
|
agentSpec: null,
|
|
43
45
|
draftSessionId: undefined,
|
|
46
|
+
isSpecLoading: false,
|
|
44
47
|
isSpecSyncing: false,
|
|
45
48
|
specError: null,
|
|
46
49
|
updateAgentSpec: () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { RemoteThreadListAdapter } from "@assistant-ui/core";
|
|
2
2
|
|
|
3
3
|
import type { AgentChatServer, Session } from "./server/types.js";
|
|
4
|
-
import { draftSessionTitle } from "./
|
|
4
|
+
import { draftSessionTitle } from "./draft/agentSpec.js";
|
|
5
5
|
import { sessionListStartTimestamp } from "./sessionListStartTimestamp.js";
|
|
6
6
|
|
|
7
7
|
const THREAD_LIST_PAGE_SIZE = 20;
|
|
@@ -63,7 +63,10 @@ export function createTrueFoundryOwnedSessionsThreadListAdapter(options: {
|
|
|
63
63
|
async rename() {},
|
|
64
64
|
async archive() {},
|
|
65
65
|
async unarchive() {},
|
|
66
|
-
async delete() {
|
|
66
|
+
async delete(remoteId) {
|
|
67
|
+
if (typeof server.deleteSession !== "function") return;
|
|
68
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
69
|
+
},
|
|
67
70
|
|
|
68
71
|
async generateTitle() {
|
|
69
72
|
return new ReadableStream();
|
|
@@ -98,4 +98,26 @@ describe("createTrueFoundryThreadListAdapter", () => {
|
|
|
98
98
|
|
|
99
99
|
expect(result.nextCursor).toBeUndefined();
|
|
100
100
|
});
|
|
101
|
+
|
|
102
|
+
it("delete calls server.deleteSession when implemented", async () => {
|
|
103
|
+
const deleteSession = vi.fn().mockResolvedValue(undefined);
|
|
104
|
+
const server = mockServer({ deleteSession });
|
|
105
|
+
const adapter = createTrueFoundryThreadListAdapter({
|
|
106
|
+
server,
|
|
107
|
+
agentName: "my-agent",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await adapter.delete("s1");
|
|
111
|
+
|
|
112
|
+
expect(deleteSession).toHaveBeenCalledWith({ sessionId: "s1" });
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("delete is a no-op when server.deleteSession is missing", async () => {
|
|
116
|
+
const adapter = createTrueFoundryThreadListAdapter({
|
|
117
|
+
server: mockServer({}),
|
|
118
|
+
agentName: "my-agent",
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await expect(adapter.delete("s1")).resolves.toBeUndefined();
|
|
122
|
+
});
|
|
101
123
|
});
|
|
@@ -50,7 +50,10 @@ export function createTrueFoundryThreadListAdapter(options: {
|
|
|
50
50
|
async rename() {},
|
|
51
51
|
async archive() {},
|
|
52
52
|
async unarchive() {},
|
|
53
|
-
async delete() {
|
|
53
|
+
async delete(remoteId) {
|
|
54
|
+
if (typeof server.deleteSession !== "function") return;
|
|
55
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
56
|
+
},
|
|
54
57
|
|
|
55
58
|
async generateTitle() {
|
|
56
59
|
return new ReadableStream();
|
package/src/types.ts
CHANGED
|
@@ -7,8 +7,7 @@ import type {
|
|
|
7
7
|
SpeechSynthesisAdapter,
|
|
8
8
|
} from "@assistant-ui/core";
|
|
9
9
|
|
|
10
|
-
import type { AgentSpec } from "./
|
|
11
|
-
import type { AgentChatServer } from "./server/types.js";
|
|
10
|
+
import type { AgentChatServer, AgentSpec } from "./server/types.js";
|
|
12
11
|
|
|
13
12
|
export type NamedAgentConfig = {
|
|
14
13
|
mode: "named";
|