@truefoundry/assistant-ui-runtime 0.1.21 → 0.1.22
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/{chunk-O7OIV5IZ.js → chunk-G4TO3HAP.js} +99 -20
- package/dist/chunk-G4TO3HAP.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +10 -3
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-CQnbe6Qh.d.ts → types-CUUft1YT.d.ts} +116 -5
- package/package.json +1 -1
- package/src/index.ts +10 -0
- package/src/plugins/truefoundry-agent-server-adapter/cp.test.ts +235 -6
- package/src/plugins/truefoundry-agent-server-adapter/cp.ts +163 -15
- package/src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts +2 -2
- package/src/plugins/truefoundry-agent-server-adapter/index.ts +26 -3
- package/src/plugins/truefoundry-agent-server-adapter/types.ts +10 -0
- package/src/plugins/truefoundry-agent-server-adapter/types.typecheck.ts +14 -0
- package/src/server/index.ts +8 -0
- package/src/server/types.ts +133 -4
- package/dist/chunk-O7OIV5IZ.js.map +0 -1
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
reasoningEffortsForModel,
|
|
20
20
|
} from "./modelReasoningEffort.js";
|
|
21
21
|
import { normalizeAgentSpecForGateway } from "./normalizeAgentSpec.js";
|
|
22
|
-
import type { TfyAgentSpec } from "./types.js";
|
|
22
|
+
import type { TfyAgentSpec, TfySaveAgentResult } from "./types.js";
|
|
23
23
|
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
// Selector rows — FE base + TFY mount fields
|
|
@@ -408,6 +408,61 @@ export function toCamelCaseDeep(value: unknown): unknown {
|
|
|
408
408
|
return value;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
+
/** Keys are user data (e.g. metadata tag names) — copied verbatim, never case-converted. */
|
|
412
|
+
function stringRecordFromCp(raw: unknown): Record<string, string> | undefined {
|
|
413
|
+
if (!isRecord(raw)) return undefined;
|
|
414
|
+
const out: Record<string, string> = {};
|
|
415
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
416
|
+
if (typeof value === "string") out[key] = value;
|
|
417
|
+
}
|
|
418
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Variable names are user keys and must survive verbatim. Values appear as
|
|
423
|
+
* plain strings in new manifests and `{ default_value }` records in older
|
|
424
|
+
* ones; both collapse to the resolved string.
|
|
425
|
+
*/
|
|
426
|
+
function variablesFromCp(raw: unknown): Record<string, string> | undefined {
|
|
427
|
+
if (!isRecord(raw)) return undefined;
|
|
428
|
+
const out: Record<string, string> = {};
|
|
429
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
430
|
+
if (typeof value === "string") {
|
|
431
|
+
out[key] = value;
|
|
432
|
+
} else if (isRecord(value) && typeof value.default_value === "string") {
|
|
433
|
+
out[key] = value.default_value;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Rebuild the gateway ResponseFormat from the wire shape. Only the envelope
|
|
441
|
+
* key changes case (`json_schema` → `jsonSchema`); the `schema` body is a
|
|
442
|
+
* user-authored JSON schema whose property names must not be rewritten.
|
|
443
|
+
*/
|
|
444
|
+
function responseFormatFromCp(raw: unknown): TfyAgentSpec["responseFormat"] {
|
|
445
|
+
if (!isRecord(raw)) return undefined;
|
|
446
|
+
if (raw.type === "text") return { type: "text" };
|
|
447
|
+
if (raw.type === "json_object") return { type: "json_object" };
|
|
448
|
+
if (raw.type !== "json_schema") return undefined;
|
|
449
|
+
const wireSchema = isRecord(raw.json_schema) ? raw.json_schema : undefined;
|
|
450
|
+
if (wireSchema == null || typeof wireSchema.name !== "string") return undefined;
|
|
451
|
+
return {
|
|
452
|
+
type: "json_schema",
|
|
453
|
+
jsonSchema: {
|
|
454
|
+
name: wireSchema.name,
|
|
455
|
+
...(typeof wireSchema.description === "string"
|
|
456
|
+
? { description: wireSchema.description }
|
|
457
|
+
: {}),
|
|
458
|
+
...(isRecord(wireSchema.schema) ? { schema: wireSchema.schema } : {}),
|
|
459
|
+
...(typeof wireSchema.strict === "boolean" || wireSchema.strict === null
|
|
460
|
+
? { strict: wireSchema.strict }
|
|
461
|
+
: {}),
|
|
462
|
+
},
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
|
|
411
466
|
/**
|
|
412
467
|
* Map a CP AgentManifest (snake_case wire) → FE AgentSpec for Edit seeding.
|
|
413
468
|
* Skills/MCP keep `{ id, name }` for draft pickers plus runtime fields
|
|
@@ -485,11 +540,39 @@ export function agentSpecFromCpManifest(manifest: unknown): TfyAgentSpec | undef
|
|
|
485
540
|
const config =
|
|
486
541
|
configRaw != null ? (toCamelCaseDeep(configRaw) as TfyAgentSpec["config"]) : undefined;
|
|
487
542
|
|
|
543
|
+
// Wire-named pass-through fields (description, messages, collaborators)
|
|
544
|
+
// need no mount remapping — one camelCase pass and a shape guard each.
|
|
545
|
+
// Guards drop malformed values instead of seeding the editor with garbage.
|
|
546
|
+
const camel = toCamelCaseDeep(manifest) as Record<string, unknown>;
|
|
547
|
+
const description =
|
|
548
|
+
typeof camel.description === "string" ? camel.description : undefined;
|
|
549
|
+
const messages = Array.isArray(camel.messages)
|
|
550
|
+
? (camel.messages as TfyAgentSpec["messages"])
|
|
551
|
+
: undefined;
|
|
552
|
+
const collaborators = Array.isArray(camel.collaborators)
|
|
553
|
+
? (camel.collaborators as TfyAgentSpec["collaborators"])
|
|
554
|
+
: undefined;
|
|
555
|
+
|
|
556
|
+
// User-keyed fields are read from the RAW manifest: their keys are data
|
|
557
|
+
// (tag names like "TFY_ALPHA_ENABLE_OPENUI", variable names like
|
|
558
|
+
// "my_city", JSON-schema property names), and case-converting them
|
|
559
|
+
// corrupts saved agents (e.g. "TFY_ALPHA…" → "tfyAlpha…" → on the next
|
|
560
|
+
// save "_t_f_y__a_l_p_h_a__…").
|
|
561
|
+
const variables = variablesFromCp(manifest.variables);
|
|
562
|
+
const tags = stringRecordFromCp(manifest.tags);
|
|
563
|
+
const responseFormat = responseFormatFromCp(manifest.response_format);
|
|
564
|
+
|
|
488
565
|
return {
|
|
489
566
|
model,
|
|
490
567
|
...(typeof manifest.instructions === "string"
|
|
491
568
|
? { instructions: manifest.instructions }
|
|
492
569
|
: {}),
|
|
570
|
+
...(description != null ? { description } : {}),
|
|
571
|
+
...(variables != null ? { variables } : {}),
|
|
572
|
+
...(messages != null ? { messages } : {}),
|
|
573
|
+
...(responseFormat != null ? { responseFormat } : {}),
|
|
574
|
+
...(tags != null ? { tags } : {}),
|
|
575
|
+
...(collaborators != null ? { collaborators } : {}),
|
|
493
576
|
...(config != null ? { config } : {}),
|
|
494
577
|
...(skills.length > 0 ? { skills } : {}),
|
|
495
578
|
...(mcpServers.length > 0 ? { mcpServers } : {}),
|
|
@@ -544,7 +627,7 @@ export async function listAgents(
|
|
|
544
627
|
// ---------------------------------------------------------------------------
|
|
545
628
|
|
|
546
629
|
/** Platform feature flags baked into every saved agent manifest. */
|
|
547
|
-
export const
|
|
630
|
+
export const SAVE_AGENT_TAGS = {
|
|
548
631
|
agent: "tfy-ai-gateway-agent",
|
|
549
632
|
TFY_ALPHA_ENABLE_OPENUI: "true",
|
|
550
633
|
TFY_ALPHA_ENABLE_ASK_USER: "true",
|
|
@@ -601,10 +684,47 @@ function skillMountForCp(mount: unknown): Record<string, unknown> {
|
|
|
601
684
|
return snake;
|
|
602
685
|
}
|
|
603
686
|
|
|
687
|
+
/**
|
|
688
|
+
* Snake-case only the response_format envelope (`jsonSchema` → `json_schema`);
|
|
689
|
+
* the `schema` body is a user-authored JSON schema whose property names must
|
|
690
|
+
* not be rewritten. Inverse of {@link responseFormatFromCp}.
|
|
691
|
+
*/
|
|
692
|
+
function responseFormatForCp(
|
|
693
|
+
responseFormat: NonNullable<TfyAgentSpec["responseFormat"]>,
|
|
694
|
+
): Record<string, unknown> {
|
|
695
|
+
const out: Record<string, unknown> = {};
|
|
696
|
+
for (const [key, value] of Object.entries(responseFormat)) {
|
|
697
|
+
if (key === "jsonSchema" && isRecord(value)) {
|
|
698
|
+
const inner: Record<string, unknown> = {};
|
|
699
|
+
for (const [innerKey, innerValue] of Object.entries(value)) {
|
|
700
|
+
inner[camelToSnakeKey(innerKey)] =
|
|
701
|
+
innerKey === "schema" ? innerValue : toSnakeCaseDeep(innerValue);
|
|
702
|
+
}
|
|
703
|
+
out.json_schema = inner;
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
out[camelToSnakeKey(key)] = toSnakeCaseDeep(value);
|
|
707
|
+
}
|
|
708
|
+
return out;
|
|
709
|
+
}
|
|
710
|
+
|
|
604
711
|
/**
|
|
605
712
|
* Build CP `manifest` for `PUT /api/svc/v1/agents`.
|
|
606
|
-
*
|
|
607
|
-
*
|
|
713
|
+
*
|
|
714
|
+
* Wire-named spec fields are snake-cased and spread so any field the host
|
|
715
|
+
* puts on the spec reaches the wire without this adapter enumerating it.
|
|
716
|
+
* tags / variables / responseFormat are pulled out FIRST because
|
|
717
|
+
* their keys are user data — snake-casing a tag named
|
|
718
|
+
* "TFY_ALPHA_ENABLE_OPENUI" would corrupt it to "_t_f_y__a_l_p_h_a__…" —
|
|
719
|
+
* and re-attached verbatim after the spread.
|
|
720
|
+
*
|
|
721
|
+
* Field order matters:
|
|
722
|
+
* 1. `...snake` — everything wire-named the host provided.
|
|
723
|
+
* 2. description / tags / collaborators — CP requires these, so
|
|
724
|
+
* platform defaults fill in only when the host omitted them.
|
|
725
|
+
* 3. mcp_servers / skills — overwrite the spread values because catalog
|
|
726
|
+
* mounts need remapping to gateway registry shapes (mcpMountForCp /
|
|
727
|
+
* skillMountForCp), which plain snake-casing cannot do.
|
|
608
728
|
*/
|
|
609
729
|
export function buildSaveAgentManifest(
|
|
610
730
|
agentName: string,
|
|
@@ -613,24 +733,51 @@ export function buildSaveAgentManifest(
|
|
|
613
733
|
const spec = normalizeAgentSpecForGateway(agentSpec);
|
|
614
734
|
const mcpServers = (spec.mcpServers ?? []).map(mcpMountForCp);
|
|
615
735
|
const skills = (spec.skills ?? []).map(skillMountForCp);
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
const description = typeof rawDescription === "string" ? rawDescription : "";
|
|
736
|
+
const { tags, variables, responseFormat, ...wireFields } = spec;
|
|
737
|
+
const snake = toSnakeCaseDeep(wireFields) as Record<string, unknown>;
|
|
619
738
|
|
|
620
739
|
return {
|
|
621
740
|
type: "truefoundry-agent",
|
|
622
741
|
name: agentName,
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
collaborators:
|
|
627
|
-
|
|
628
|
-
|
|
742
|
+
...snake,
|
|
743
|
+
description: typeof snake.description === "string" ? snake.description : "",
|
|
744
|
+
tags: tags ?? { ...SAVE_AGENT_TAGS },
|
|
745
|
+
collaborators: Array.isArray(snake.collaborators)
|
|
746
|
+
? snake.collaborators
|
|
747
|
+
: [...SAVE_AGENT_COLLABORATORS],
|
|
748
|
+
...(variables != null ? { variables } : {}),
|
|
749
|
+
...(responseFormat != null
|
|
750
|
+
? { response_format: responseFormatForCp(responseFormat) }
|
|
751
|
+
: {}),
|
|
629
752
|
...(mcpServers.length > 0 ? { mcp_servers: mcpServers } : {}),
|
|
630
753
|
...(skills.length > 0 ? { skills } : {}),
|
|
631
754
|
};
|
|
632
755
|
}
|
|
633
756
|
|
|
757
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
758
|
+
return typeof value === "string" && value !== "" ? value : undefined;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Normalize CP save responses into
|
|
763
|
+
* `{ agentId, versionId }`. Observed live shapes (both camelCase, wrapped):
|
|
764
|
+
* { data: { id: "<versionId>", agentId: "<agentId>", fqn, version, … } } //agent-playground
|
|
765
|
+
* { data: { id: "<agentId>", name, manifest } } — no separate version //trueforge
|
|
766
|
+
* `id` is a version id only when a distinct `agentId` accompanies it;
|
|
767
|
+
* otherwise `id` is the agent itself and no version id is known.
|
|
768
|
+
*/
|
|
769
|
+
export function saveAgentResultFromCp(raw: unknown): TfySaveAgentResult {
|
|
770
|
+
const root = isRecord(raw) ? raw : {};
|
|
771
|
+
const data = isRecord(root.data) ? root.data : {};
|
|
772
|
+
const agentId = nonEmptyString(data.agentId) ?? nonEmptyString(data.id);
|
|
773
|
+
const versionId =
|
|
774
|
+
nonEmptyString(data.agentId) != null ? nonEmptyString(data.id) : undefined;
|
|
775
|
+
return {
|
|
776
|
+
...(agentId != null ? { agentId } : {}),
|
|
777
|
+
...(versionId != null ? { versionId } : {}),
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
|
|
634
781
|
/**
|
|
635
782
|
* Upsert a named agent on the Control Plane.
|
|
636
783
|
* `PUT /api/svc/v1/agents` with `{ manifest }` — name is the upsert key.
|
|
@@ -638,11 +785,12 @@ export function buildSaveAgentManifest(
|
|
|
638
785
|
export async function saveAgent(
|
|
639
786
|
opts: CpCredentials,
|
|
640
787
|
req: SaveAgentRequest<TfyAgentSpec>,
|
|
641
|
-
): Promise<
|
|
788
|
+
): Promise<TfySaveAgentResult> {
|
|
642
789
|
const manifest = buildSaveAgentManifest(req.agentName, req.agentSpec);
|
|
643
|
-
|
|
790
|
+
const raw = await cpFetch<unknown>(opts, "/api/svc/v1/agents", {
|
|
644
791
|
method: "PUT",
|
|
645
792
|
headers: { "Content-Type": "application/json" },
|
|
646
793
|
body: JSON.stringify({ manifest }),
|
|
647
794
|
});
|
|
795
|
+
return saveAgentResultFromCp(raw);
|
|
648
796
|
}
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
createTrueFoundryChatServer,
|
|
16
16
|
type TrueFoundryChatServer,
|
|
17
17
|
} from "./chatServer.js";
|
|
18
|
-
import type { TfyAgentSpec } from "./types.js";
|
|
18
|
+
import type { TfyAgentSpec, TfySaveAgentResult } from "./types.js";
|
|
19
19
|
|
|
20
20
|
export type CreateTrueFoundryAgentUIServerOptions = {
|
|
21
21
|
apiKey: string;
|
|
@@ -37,7 +37,7 @@ export type TrueFoundryAgentUIServer<TSpec extends TfyAgentSpec = TfyAgentSpec>
|
|
|
37
37
|
TfySkillSelectorEntry,
|
|
38
38
|
TfyConnectorSelectorEntry,
|
|
39
39
|
TfyAgentSelectorEntry,
|
|
40
|
-
|
|
40
|
+
TfySaveAgentResult
|
|
41
41
|
>;
|
|
42
42
|
|
|
43
43
|
function credentialsKey(opts: CreateTrueFoundryAgentUIServerOptions): string {
|
|
@@ -17,9 +17,32 @@ export {
|
|
|
17
17
|
|
|
18
18
|
export {
|
|
19
19
|
type RequireApprovalToolSelectorItem,
|
|
20
|
-
type RequireApprovalToolsSelectorTag,
|
|
21
|
-
type
|
|
22
|
-
type
|
|
20
|
+
type RequireApprovalToolsSelectorTag,
|
|
21
|
+
type TfyAgentSpec,
|
|
22
|
+
type TfyCollaborator,
|
|
23
|
+
type TfyCreateSessionRequest,
|
|
24
|
+
type TfyFinishReason,
|
|
25
|
+
type TfyListSessionsParams,
|
|
26
|
+
type TfyMcpServerInitInfo,
|
|
27
|
+
type TfyMcpServerMount,
|
|
28
|
+
type TfyMcpToolInfo,
|
|
29
|
+
type TfyModelMessageUsage,
|
|
30
|
+
type TfyModelParams,
|
|
31
|
+
type TfyResponseFormat,
|
|
32
|
+
type TfyRuntimeConfig,
|
|
33
|
+
type TfySaveAgentResult,
|
|
34
|
+
type TfySession,
|
|
35
|
+
type TfySkillMount,
|
|
36
|
+
type TfySubject,
|
|
37
|
+
type TfySystemToolInfo,
|
|
38
|
+
type TfyThreadState,
|
|
39
|
+
type TfyToolInfo,
|
|
40
|
+
type TfyTurn,
|
|
41
|
+
type TfyTurnCancelledReason,
|
|
42
|
+
type TfyTurnState,
|
|
43
|
+
type TfyTurnStateDoneOutput,
|
|
44
|
+
type ToolsSelectorItem,
|
|
45
|
+
type ToolsSelectorTag,
|
|
23
46
|
} from "./types.js";
|
|
24
47
|
|
|
25
48
|
export {
|
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
AgentSpec,
|
|
17
17
|
CreateSessionRequest,
|
|
18
18
|
ListSessionsParams,
|
|
19
|
+
SaveAgentResult,
|
|
19
20
|
Session,
|
|
20
21
|
Turn,
|
|
21
22
|
TurnState,
|
|
@@ -63,6 +64,11 @@ export type TfyMcpServerMount = RuntimeMcpServerMount & TruefoundryGatewayApi.Mc
|
|
|
63
64
|
// AgentSpec — the concrete TrueFoundry agent definition
|
|
64
65
|
// ---------------------------------------------------------------------------
|
|
65
66
|
|
|
67
|
+
export interface TfyCollaborator {
|
|
68
|
+
subject: string;
|
|
69
|
+
roleId: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
66
72
|
export interface TfyAgentSpec
|
|
67
73
|
extends AgentSpec<
|
|
68
74
|
TruefoundryGatewayApi.Model,
|
|
@@ -72,8 +78,12 @@ export interface TfyAgentSpec
|
|
|
72
78
|
> {
|
|
73
79
|
responseFormat?: TruefoundryGatewayApi.ResponseFormat;
|
|
74
80
|
messages?: TruefoundryGatewayApi.AgentSpecUserMessage[];
|
|
81
|
+
tags?: Record<string, string>;
|
|
82
|
+
collaborators?: TfyCollaborator[];
|
|
75
83
|
}
|
|
76
84
|
|
|
85
|
+
export type TfySaveAgentResult = SaveAgentResult;
|
|
86
|
+
|
|
77
87
|
// ---------------------------------------------------------------------------
|
|
78
88
|
// Turn — runtime base narrowed to the gateway's concrete state shapes
|
|
79
89
|
// ---------------------------------------------------------------------------
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
TfyAgentSpec,
|
|
16
16
|
TfyFinishReason,
|
|
17
17
|
TfyMcpServerMount,
|
|
18
|
+
TfySaveAgentResult,
|
|
18
19
|
TfySkillMount,
|
|
19
20
|
TfySubject,
|
|
20
21
|
TfyTurn,
|
|
@@ -162,3 +163,16 @@ export const withEndTimestamp: NonNullable<
|
|
|
162
163
|
startTimestamp: "2026-01-01T00:00:00Z",
|
|
163
164
|
endTimestamp: "2026-02-01T00:00:00Z",
|
|
164
165
|
};
|
|
166
|
+
|
|
167
|
+
export const savedAgent: TfyAgentSpec = {
|
|
168
|
+
model: { name: "openai-main/gpt-4.1" },
|
|
169
|
+
description: "Demo",
|
|
170
|
+
tags: { env: "test" },
|
|
171
|
+
collaborators: [{ subject: "team:everyone", roleId: "agent-access" }],
|
|
172
|
+
variables: { city: "Berlin" },
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export const saveResult: TfySaveAgentResult = {
|
|
176
|
+
agentId: "ag_1",
|
|
177
|
+
versionId: "ver_1",
|
|
178
|
+
};
|
package/src/server/index.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type {
|
|
|
35
35
|
UserToolResponseEvent,
|
|
36
36
|
TurnInputItem,
|
|
37
37
|
TurnStateRunning,
|
|
38
|
+
TurnDoneMetrics,
|
|
38
39
|
TurnStateDone,
|
|
39
40
|
TurnStateCancelled,
|
|
40
41
|
TurnStateError,
|
|
@@ -94,6 +95,13 @@ export type {
|
|
|
94
95
|
UpdateSandboxProviderRequest,
|
|
95
96
|
SandboxCatalogServer,
|
|
96
97
|
CatalogServer,
|
|
98
|
+
AgentDetail,
|
|
99
|
+
CodeSnippetSampleCode,
|
|
100
|
+
CodeSnippet,
|
|
101
|
+
SessionListMetrics,
|
|
102
|
+
SessionListEntry,
|
|
103
|
+
ListSessionEventsParams,
|
|
104
|
+
AgentSessionsServer,
|
|
97
105
|
AgentUIServerPort,
|
|
98
106
|
AgentUIServer,
|
|
99
107
|
} from "./types.js";
|
package/src/server/types.ts
CHANGED
|
@@ -132,6 +132,7 @@ export interface AgentSpec<
|
|
|
132
132
|
config?: TConfig;
|
|
133
133
|
instructions?: string;
|
|
134
134
|
variables?: Record<string, string>;
|
|
135
|
+
description?: string;
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
// ---------------------------------------------------------------------------
|
|
@@ -179,10 +180,12 @@ export type PageParams = {
|
|
|
179
180
|
};
|
|
180
181
|
|
|
181
182
|
export interface ListSessionsParams extends PageParams {
|
|
182
|
-
/** Host-owned agent identity filter.
|
|
183
|
+
/** Host-owned agent identity filter. Omit for all sessions (current user). */
|
|
183
184
|
agentId?: string;
|
|
184
|
-
/**
|
|
185
|
+
/** Inclusive lower bound on session activity (ISO-8601). */
|
|
185
186
|
startTimestamp?: string;
|
|
187
|
+
/** Inclusive upper bound on session activity (ISO-8601). */
|
|
188
|
+
endTimestamp?: string;
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
export type PreviousTurnIdInput = "auto" | "none" | string;
|
|
@@ -228,11 +231,26 @@ export type TurnInputItem =
|
|
|
228
231
|
|
|
229
232
|
export type TurnStateRunning = { status: "running" };
|
|
230
233
|
|
|
234
|
+
/**
|
|
235
|
+
* Aggregated token metrics on a finished turn (`turn.done.state.metrics`).
|
|
236
|
+
* Host maps wire snake_case (`total_input_tokens`, …) → camelCase here.
|
|
237
|
+
*/
|
|
238
|
+
export interface TurnDoneMetrics {
|
|
239
|
+
totalInputTokens: number;
|
|
240
|
+
totalOutputTokens: number;
|
|
241
|
+
totalTokens: number;
|
|
242
|
+
totalCacheReadTokens: number;
|
|
243
|
+
totalCacheWriteTokens: number;
|
|
244
|
+
totalReasoningTokens: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
231
247
|
export type TurnStateDone = {
|
|
232
248
|
status: "done";
|
|
233
249
|
output?: unknown;
|
|
234
250
|
requiredActions?: ActionRequiredEvent[];
|
|
235
251
|
completedAt: string;
|
|
252
|
+
/** Present when the host reports per-turn token totals. */
|
|
253
|
+
metrics?: TurnDoneMetrics;
|
|
236
254
|
};
|
|
237
255
|
|
|
238
256
|
export type TurnStateCancelled = {
|
|
@@ -352,6 +370,8 @@ export interface SaveAgentRequest<TSpec extends AgentSpec = AgentSpec> {
|
|
|
352
370
|
export interface SaveAgentResult {
|
|
353
371
|
/** Immutable id allocated by the host registry. */
|
|
354
372
|
agentId?: string;
|
|
373
|
+
/** Version id allocated by the host registry for this save. */
|
|
374
|
+
versionId?: string;
|
|
355
375
|
/** Timestamp returned when the active mutable session was updated. */
|
|
356
376
|
sessionUpdatedAt?: string;
|
|
357
377
|
}
|
|
@@ -775,20 +795,129 @@ export interface CatalogServer<
|
|
|
775
795
|
sandboxCatalog?: TSandboxCatalog;
|
|
776
796
|
}
|
|
777
797
|
|
|
798
|
+
// ---------------------------------------------------------------------------
|
|
799
|
+
// AgentSessions — optional agent-detail shell (Overview + sessions under agent)
|
|
800
|
+
// ---------------------------------------------------------------------------
|
|
801
|
+
|
|
802
|
+
/**
|
|
803
|
+
* Published agent identity + spec for the agent-detail Overview (read-only).
|
|
804
|
+
* Host widens `TSpec` (and may extend this DTO) for mounts / config / extras.
|
|
805
|
+
*/
|
|
806
|
+
export interface AgentDetail<TSpec extends AgentSpec = AgentSpec> {
|
|
807
|
+
agentId: string;
|
|
808
|
+
/** Display name (e.g. "release-notes-writer"). */
|
|
809
|
+
name: string;
|
|
810
|
+
agentSpec: TSpec;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
/** Stream vs non-stream bodies for one language on the Use In Code tab. */
|
|
814
|
+
export interface CodeSnippetSampleCode {
|
|
815
|
+
stream: string;
|
|
816
|
+
nonStream: string;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
* One language row for Use In Code.
|
|
821
|
+
* Host maps wire `sample_code` / `non_stream` → camelCase here.
|
|
822
|
+
*/
|
|
823
|
+
export interface CodeSnippet<
|
|
824
|
+
TSample extends CodeSnippetSampleCode = CodeSnippetSampleCode,
|
|
825
|
+
> {
|
|
826
|
+
/** Sidebar label (e.g. "TypeScript"). */
|
|
827
|
+
labelName: string;
|
|
828
|
+
/** Highlighter / tab id (e.g. "typescript"). */
|
|
829
|
+
language: string;
|
|
830
|
+
icon?: string;
|
|
831
|
+
sampleCode: TSample;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Aggregated session metrics for the sessions list sidebar.
|
|
836
|
+
* Host maps wire snake_case (`total_turns`, `total_cost_in_usd`, …) → camelCase.
|
|
837
|
+
*/
|
|
838
|
+
export interface SessionListMetrics {
|
|
839
|
+
totalTurns: number;
|
|
840
|
+
totalCostInUsd: number;
|
|
841
|
+
totalDurationMs: number;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* One row in the Agent Sessions list (left pane).
|
|
846
|
+
*
|
|
847
|
+
* Binding: `agentName` → named / immutable agent; `agentSpec` → mutable / draft.
|
|
848
|
+
* Host may send one, both, or neither depending on how the session was created.
|
|
849
|
+
*/
|
|
850
|
+
export interface SessionListEntry<TSpec extends AgentSpec = AgentSpec> {
|
|
851
|
+
id: string;
|
|
852
|
+
title?: string | null;
|
|
853
|
+
createdAt: string;
|
|
854
|
+
updatedAt: string;
|
|
855
|
+
lastActivityAt: string;
|
|
856
|
+
metrics: SessionListMetrics;
|
|
857
|
+
/** Present when bound to a published (immutable) agent. */
|
|
858
|
+
agentName?: string | null;
|
|
859
|
+
/** Present when bound to a mutable / draft agent spec. */
|
|
860
|
+
agentSpec?: TSpec;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/** Params for `AgentSessionsServer.listSessionEvents` (session event timeline). */
|
|
864
|
+
export interface ListSessionEventsParams extends Pick<PageParams, "limit" | "pageToken"> {
|
|
865
|
+
sessionId: string;
|
|
866
|
+
}
|
|
867
|
+
|
|
778
868
|
/**
|
|
779
|
-
*
|
|
869
|
+
* Optional plug-in for agent-detail UI: Overview, Use In Code, sessions list,
|
|
870
|
+
* and per-session event timeline. Omit `sessions` on `AgentUIServerPort` when
|
|
871
|
+
* the host has no agent-detail surface.
|
|
872
|
+
*
|
|
873
|
+
* Read-only — create/update/delete stay on `AgentChatServer` / `AgentBuilderServer`.
|
|
874
|
+
*/
|
|
875
|
+
export interface AgentSessionsServer<
|
|
876
|
+
TSpec extends AgentSpec = AgentSpec,
|
|
877
|
+
TDetail extends AgentDetail<TSpec> = AgentDetail<TSpec>,
|
|
878
|
+
TSnippet extends CodeSnippet = CodeSnippet,
|
|
879
|
+
TListEntry extends SessionListEntry<TSpec> = SessionListEntry<TSpec>,
|
|
880
|
+
TList extends ListSessionsParams = ListSessionsParams,
|
|
881
|
+
> {
|
|
882
|
+
/** Fetch published agent details by id for the Overview tab. */
|
|
883
|
+
getAgent(req: { agentId: string }): Promise<TDetail>;
|
|
884
|
+
/** Fetch Use In Code snippets for the agent (one row per language). */
|
|
885
|
+
getCodeSnippets(req: { agentId: string }): Promise<TSnippet[]>;
|
|
886
|
+
/**
|
|
887
|
+
* List sessions for the current user. Pass `agentId` to scope to one agent;
|
|
888
|
+
* omit for all sessions. Use `startTimestamp` / `endTimestamp` for date filters.
|
|
889
|
+
*/
|
|
890
|
+
listSessions(req?: TList): Promise<ListResult<TListEntry>>;
|
|
891
|
+
/**
|
|
892
|
+
* Fetch the session event timeline (right pane). Paginate with `pageToken`
|
|
893
|
+
* until exhausted; rebuild turns from `turn.created` / `turn.done` +
|
|
894
|
+
* nested `TurnEvent`s. Per-turn token metrics live on `turn.done.state.metrics`.
|
|
895
|
+
*/
|
|
896
|
+
listSessionEvents(
|
|
897
|
+
req: ListSessionEventsParams,
|
|
898
|
+
): Promise<ListResult<SessionEventItem>>;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* Composed host port: chat + builder + optional settings catalog + optional
|
|
903
|
+
* agent-detail / sessions shell.
|
|
780
904
|
*
|
|
781
905
|
* `catalog` is optional — if the host passes it, settings UI can call
|
|
782
906
|
* `useCatalogServer()` / show modelCatalog, connectorCatalog, and skillCatalog;
|
|
783
907
|
* if omitted, those surfaces stay hidden.
|
|
784
908
|
*
|
|
909
|
+
* `sessions` is optional — if the host passes it, agent-detail UI can call
|
|
910
|
+
* `useAgentSessionsServer()` / Overview + sessions under an agent; if omitted,
|
|
911
|
+
* that surface stays hidden.
|
|
912
|
+
*
|
|
785
913
|
* trueforge-ui re-exports this as `AgentUIServer`.
|
|
786
914
|
*/
|
|
787
915
|
export type AgentUIServerPort<
|
|
788
916
|
TChat extends AgentChatServer = AgentChatServer,
|
|
789
917
|
TBuilder extends AgentBuilderServer = AgentBuilderServer,
|
|
790
918
|
TCatalog extends CatalogServer = CatalogServer,
|
|
791
|
-
|
|
919
|
+
TSessions extends AgentSessionsServer = AgentSessionsServer,
|
|
920
|
+
> = TChat & TBuilder & { catalog?: TCatalog; sessions?: TSessions };
|
|
792
921
|
|
|
793
922
|
/** Host-facing alias used by trueforge-ui. */
|
|
794
923
|
export type AgentUIServer = AgentUIServerPort;
|