@vertesia/common 1.5.0-dev.20260722.120446Z → 1.5.0-dev.20260725.083715Z

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/common",
3
- "version": "1.5.0-dev.20260722.120446Z",
3
+ "version": "1.5.0-dev.20260725.083715Z",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -17,14 +17,14 @@
17
17
  }
18
18
  },
19
19
  "devDependencies": {
20
- "rolldown": "1.1.5",
20
+ "rolldown": "1.2.0",
21
21
  "typescript": "^6.0.3",
22
22
  "vitest": "^4.1.10",
23
23
  "@vertesia/tsconfig": "0.1.0"
24
24
  },
25
25
  "dependencies": {
26
26
  "ajv": "^8.20.0",
27
- "@llumiverse/common": "1.5.0-dev.20260722.112223Z"
27
+ "@llumiverse/common": "1.5.0-dev.20260725.065646Z"
28
28
  },
29
29
  "repository": {
30
30
  "type": "git",
@@ -39,7 +39,7 @@
39
39
  "ai",
40
40
  "typescript"
41
41
  ],
42
- "gitHead": "203c30e5a8ddc583ac9f1acce0f5445eb38a9551",
42
+ "gitHead": "57bcc2f27dd17b3387f27c18e89329c4c37f98ac",
43
43
  "scripts": {
44
44
  "lint": "biome lint src",
45
45
  "test": "vitest run",
@@ -0,0 +1,100 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { type AgentResourceReference, getResourcesFromToolResult, normalizeAgentResources } from './interaction.js';
3
+ import { AgentMessageType, getResourcesFromMessage } from './store/workflow.js';
4
+
5
+ const validRef: AgentResourceReference = {
6
+ type: 'document',
7
+ id: 'doc-1',
8
+ label: 'My Document',
9
+ action: 'created',
10
+ };
11
+
12
+ describe('normalizeAgentResources', () => {
13
+ it('returns an empty array for non-array input', () => {
14
+ expect(normalizeAgentResources(undefined)).toEqual([]);
15
+ expect(normalizeAgentResources(null)).toEqual([]);
16
+ expect(normalizeAgentResources('nope')).toEqual([]);
17
+ expect(normalizeAgentResources({})).toEqual([]);
18
+ });
19
+
20
+ it('keeps a well-formed reference', () => {
21
+ expect(normalizeAgentResources([validRef])).toEqual([validRef]);
22
+ });
23
+
24
+ it('preserves revision_id when present and non-empty', () => {
25
+ const ref = { ...validRef, revision_id: 'rev-9' };
26
+ expect(normalizeAgentResources([ref])).toEqual([ref]);
27
+ });
28
+
29
+ it('drops an empty revision_id rather than keeping it', () => {
30
+ const result = normalizeAgentResources([{ ...validRef, revision_id: '' }]);
31
+ expect(result[0]).not.toHaveProperty('revision_id');
32
+ });
33
+
34
+ it('falls back to the id when the label is missing or empty', () => {
35
+ const result = normalizeAgentResources([{ type: 'collection', id: 'col-1', action: 'updated' }]);
36
+ expect(result).toEqual([{ type: 'collection', id: 'col-1', label: 'col-1', action: 'updated' }]);
37
+ });
38
+
39
+ it('drops entries with an unknown type or action', () => {
40
+ const result = normalizeAgentResources([
41
+ { type: 'artifact', id: 'a', label: 'a', action: 'created' },
42
+ { type: 'document', id: 'd', label: 'd', action: 'viewed' },
43
+ { type: 'document', id: '', label: 'd', action: 'created' },
44
+ validRef,
45
+ ]);
46
+ expect(result).toEqual([validRef]);
47
+ });
48
+
49
+ it('accepts every supported resource type', () => {
50
+ const types = [
51
+ 'document',
52
+ 'collection',
53
+ 'content_type',
54
+ 'interaction',
55
+ 'prompt',
56
+ 'agent',
57
+ 'workflow',
58
+ 'process',
59
+ 'process_run',
60
+ 'interaction_run',
61
+ 'view',
62
+ ] as const;
63
+ const input = types.map((type, i) => ({ type, id: `id-${i}`, label: `L${i}`, action: 'created' }));
64
+ expect(normalizeAgentResources(input)).toHaveLength(types.length);
65
+ });
66
+ });
67
+
68
+ describe('getResourcesFromToolResult', () => {
69
+ it('reads resources from result meta', () => {
70
+ expect(getResourcesFromToolResult({ meta: { resources: [validRef] } })).toEqual([validRef]);
71
+ });
72
+
73
+ it('returns an empty array when meta or resources are absent', () => {
74
+ expect(getResourcesFromToolResult({})).toEqual([]);
75
+ expect(getResourcesFromToolResult({ meta: {} })).toEqual([]);
76
+ });
77
+ });
78
+
79
+ describe('getResourcesFromMessage', () => {
80
+ it('reads resources from message details', () => {
81
+ const msg = {
82
+ timestamp: 0,
83
+ workflow_run_id: 'run-1',
84
+ type: AgentMessageType.THOUGHT,
85
+ message: '',
86
+ details: { event_class: 'activity', resources: [validRef] },
87
+ };
88
+ expect(getResourcesFromMessage(msg)).toEqual([validRef]);
89
+ });
90
+
91
+ it('returns an empty array when details or resources are absent', () => {
92
+ const msg = {
93
+ timestamp: 0,
94
+ workflow_run_id: 'run-1',
95
+ type: AgentMessageType.COMPLETE,
96
+ message: '',
97
+ };
98
+ expect(getResourcesFromMessage(msg)).toEqual([]);
99
+ });
100
+ });
package/src/apps.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import type { JSONObject, JSONSchema, ToolDefinition } from '@llumiverse/common';
2
2
  import type { AppDashboardDefinition } from './data-platform.js';
3
3
  import type { CatalogInteractionRef } from './interaction.js';
4
- import type { DSLActivityOptions, InCodeProcessDefinition, InCodeTypeDefinition } from './store/index.js';
4
+ import type {
5
+ AgentRunSearchHit,
6
+ DSLActivityOptions,
7
+ InCodeProcessDefinition,
8
+ InCodeTypeDefinition,
9
+ } from './store/index.js';
5
10
  import type { InCodeViewDefinition } from './views.js';
6
11
 
7
12
  /** Allowed values for AppUINavItem.preferredSection */
@@ -552,6 +557,8 @@ export interface AppVersionRecord {
552
557
  promoted?: boolean;
553
558
  target?: AppVersionTarget;
554
559
  agent_run_id?: string;
560
+ /** Development task that produced this version, when built by the app assistant. */
561
+ development_task_id?: string;
555
562
  /** Temporal workflow that produced this version. */
556
563
  build_workflow_id?: string;
557
564
  /** Temporal run that produced this version. */
@@ -597,6 +604,8 @@ export interface UpsertAppVersionRequest {
597
604
  state?: AppVersionState;
598
605
  target?: AppVersionTarget;
599
606
  agent_run_id?: string;
607
+ /** Development task that produced this version, when built by the app assistant. */
608
+ development_task_id?: string;
600
609
  build_workflow_id?: string;
601
610
  build_workflow_run_id?: string;
602
611
  sandbox_id?: string;
@@ -721,6 +730,7 @@ export interface AppScaffoldWorkflowInput extends StartAppScaffoldRequest {}
721
730
  export interface AppScaffoldWorkflowResult {
722
731
  app_id: string;
723
732
  app_record_id?: string;
733
+ installation_id?: string;
724
734
  git_url?: string;
725
735
  source_git?: AppVersionGitSource;
726
736
  files?: number;
@@ -741,6 +751,7 @@ export interface AppScaffoldProgress {
741
751
  step: string;
742
752
  app_id?: string;
743
753
  app_record_id?: string;
754
+ installation_id?: string;
744
755
  git_url?: string;
745
756
  files?: number;
746
757
  initial_version_build?: StartAppBuildResponse;
@@ -1063,6 +1074,44 @@ export interface AppRepoRefs {
1063
1074
  tags: AppRepoRef[];
1064
1075
  }
1065
1076
 
1077
+ /** A mutable app development task represented by an `agent/*` Git branch. */
1078
+ export interface AppDevelopmentTask {
1079
+ /** Task slug derived from the branch name. */
1080
+ id: string;
1081
+ /** Complete Git branch name. */
1082
+ branch: string;
1083
+ /** Commit currently at the branch head. */
1084
+ source_commit: string;
1085
+ /** Branch-head commit date, when available. */
1086
+ commit_date?: string;
1087
+ }
1088
+
1089
+ /** Git-backed development tasks and the branch used for new tasks by default. */
1090
+ export interface AppDevelopmentTaskList {
1091
+ /** Repository default branch, when resolvable. */
1092
+ default_branch?: string;
1093
+ tasks: AppDevelopmentTask[];
1094
+ }
1095
+
1096
+ /** Development task details, including the latest parent assistant run when one exists. */
1097
+ export interface AppDevelopmentTaskDetails extends AppDevelopmentTask {
1098
+ /** Latest Studio Assistant run started for this task branch. */
1099
+ agent_run?: AgentRunSearchHit;
1100
+ }
1101
+
1102
+ /** Request to create a branch from an existing branch, tag, or commit. */
1103
+ export interface CreateAppRepoBranchRequest {
1104
+ name: string;
1105
+ source_ref: string;
1106
+ }
1107
+
1108
+ /** A newly created app repository branch. */
1109
+ export interface AppRepoBranch {
1110
+ name: string;
1111
+ commit: string;
1112
+ source_ref: string;
1113
+ }
1114
+
1066
1115
  /**
1067
1116
  * Canonical package scopes, including the catch-all `all`. The public type is derived
1068
1117
  * from this list so request parsing and TypeScript cannot drift.
@@ -91,6 +91,8 @@ export interface TextFallbackOptions {
91
91
  export interface ExecutionEnvironmentSettings {
92
92
  [key: string]: unknown;
93
93
  bucket_access_principal?: string;
94
+ /** Custom HTTP headers sent by OpenAI-compatible environments. */
95
+ default_headers?: Record<string, string>;
94
96
  }
95
97
 
96
98
  /**
@@ -717,6 +717,21 @@ export {
717
717
  } from './email.js';
718
718
  // ================= end user communication channels ====================
719
719
 
720
+ /**
721
+ * A tool invocation executed before the first model turn of a conversation.
722
+ * Results are injected into the initial context so the agent starts with them in hand.
723
+ */
724
+ export interface InitialToolCall {
725
+ /** Stable identifier used to make initialization replay-safe. */
726
+ id: string;
727
+ /** Read-only builtin activity tool name. Skills are configured separately through initial_skills. */
728
+ tool: string;
729
+ /** Tool input parameters. */
730
+ input?: Record<string, unknown>;
731
+ /** Whether a failed initialization call aborts the conversation start. */
732
+ on_error?: 'fail' | 'continue';
733
+ }
734
+
720
735
  export interface AsyncConversationExecutionPayload extends AsyncExecutionPayloadBase {
721
736
  type: 'conversation';
722
737
 
@@ -735,6 +750,28 @@ export interface AsyncConversationExecutionPayload extends AsyncExecutionPayload
735
750
  */
736
751
  tool_names?: string[];
737
752
 
753
+ /**
754
+ * Builtin system skills to activate at conversation start. Their related tools are
755
+ * exposed from the first turn and their instructions are injected into the initial
756
+ * context, replacing the learn_<skill> round-trip.
757
+ */
758
+ initial_skills?: string[];
759
+
760
+ /**
761
+ * Tool calls executed before the first model turn. Results are injected into the
762
+ * initial context. These run sequentially with the caller's authority before the
763
+ * first model turn. Only a bounded set of read/hydration tools is accepted.
764
+ */
765
+ initial_tool_calls?: InitialToolCall[];
766
+
767
+ /**
768
+ * Hard denylist of tool names for this conversation. Excluded tools are never
769
+ * exposed to the model and are refused at execution time, even when a skill or
770
+ * tool refresh would otherwise unlock them. Takes precedence over tool_names,
771
+ * initial_skills, and skill-based tool activation.
772
+ */
773
+ excluded_tools?: string[];
774
+
738
775
  /**
739
776
  * The maximum number of iterations in case of a conversation. If <=0 the default of 20 will be used.
740
777
  */
@@ -973,6 +1010,52 @@ interface ResumeConversationPayload {
973
1010
  asyncCompletion?: AsyncCompletionOptions;
974
1011
  }
975
1012
 
1013
+ /**
1014
+ * The kinds of Vertesia resource an agent tool can report having created, updated, or deleted.
1015
+ * Restricted to resources that have a real detail route to navigate to — do not emit a reference
1016
+ * for a mutation with no meaningful navigation target. Add new kinds only once their route exists.
1017
+ */
1018
+ export type AgentResourceType =
1019
+ | 'document'
1020
+ | 'collection'
1021
+ | 'content_type'
1022
+ | 'interaction'
1023
+ | 'prompt'
1024
+ | 'agent'
1025
+ | 'workflow'
1026
+ | 'process'
1027
+ | 'process_run'
1028
+ | 'interaction_run'
1029
+ | 'view';
1030
+
1031
+ export type AgentResourceAction = 'created' | 'updated' | 'deleted';
1032
+
1033
+ /**
1034
+ * A navigable reference to a resource an agent tool mutated. Tools return these as tool-result
1035
+ * metadata (see {@link ToolResultMeta.resources}); the conversation runtime promotes them onto the
1036
+ * tool's completed lifecycle message so the UI can render deterministic deep links and an
1037
+ * end-of-turn "resources changed" summary — independent of any link the model writes in prose.
1038
+ */
1039
+ export interface AgentResourceReference {
1040
+ type: AgentResourceType;
1041
+ /** The resource id used to build its detail route. */
1042
+ id: string;
1043
+ /** Human-readable label captured at mutation time (e.g. the document name). */
1044
+ label: string;
1045
+ action: AgentResourceAction;
1046
+ /** Set when the mutation produced a new revision, enabling a "view changes" affordance. */
1047
+ revision_id?: string;
1048
+ }
1049
+
1050
+ /**
1051
+ * Metadata a tool executor may attach to its result. Kept as an open record for forward
1052
+ * compatibility while typing the fields the runtime interprets.
1053
+ */
1054
+ export interface ToolResultMeta extends Record<string, unknown> {
1055
+ /** Resources this tool created/updated/deleted, surfaced as deep links in the UI. */
1056
+ resources?: AgentResourceReference[];
1057
+ }
1058
+
976
1059
  export interface ToolResultContent {
977
1060
  content: string;
978
1061
  /**
@@ -992,7 +1075,54 @@ export interface ToolResultContent {
992
1075
  /**
993
1076
  * Can contain metadata returned by the tool executor.
994
1077
  */
995
- meta?: Record<string, unknown>;
1078
+ meta?: ToolResultMeta;
1079
+ }
1080
+
1081
+ const AGENT_RESOURCE_TYPES: readonly AgentResourceType[] = [
1082
+ 'document',
1083
+ 'collection',
1084
+ 'content_type',
1085
+ 'interaction',
1086
+ 'prompt',
1087
+ 'agent',
1088
+ 'workflow',
1089
+ 'process',
1090
+ 'process_run',
1091
+ 'interaction_run',
1092
+ 'view',
1093
+ ];
1094
+
1095
+ const AGENT_RESOURCE_ACTIONS: readonly AgentResourceAction[] = ['created', 'updated', 'deleted'];
1096
+
1097
+ /**
1098
+ * Validate and normalize an untrusted value into a clean list of resource references. References
1099
+ * cross the wire and may originate from external/MCP tools, so malformed entries are dropped
1100
+ * rather than throwing, and an empty/absent label falls back to the id.
1101
+ */
1102
+ export function normalizeAgentResources(value: unknown): AgentResourceReference[] {
1103
+ if (!Array.isArray(value)) return [];
1104
+ const result: AgentResourceReference[] = [];
1105
+ for (const entry of value) {
1106
+ if (!entry || typeof entry !== 'object') continue;
1107
+ const ref = entry as Record<string, unknown>;
1108
+ const { type, id, label, action, revision_id } = ref;
1109
+ if (typeof type !== 'string' || !AGENT_RESOURCE_TYPES.includes(type as AgentResourceType)) continue;
1110
+ if (typeof id !== 'string' || id.length === 0) continue;
1111
+ if (typeof action !== 'string' || !AGENT_RESOURCE_ACTIONS.includes(action as AgentResourceAction)) continue;
1112
+ result.push({
1113
+ type: type as AgentResourceType,
1114
+ id,
1115
+ label: typeof label === 'string' && label.length > 0 ? label : id,
1116
+ action: action as AgentResourceAction,
1117
+ ...(typeof revision_id === 'string' && revision_id.length > 0 ? { revision_id } : {}),
1118
+ });
1119
+ }
1120
+ return result;
1121
+ }
1122
+
1123
+ /** Extract the normalized resource references a tool declared in its result metadata. */
1124
+ export function getResourcesFromToolResult(result: Pick<ToolResultContent, 'meta'>): AgentResourceReference[] {
1125
+ return normalizeAgentResources(result.meta?.resources);
996
1126
  }
997
1127
 
998
1128
  export interface ToolResult extends ToolResultContent {
@@ -16,6 +16,7 @@ import type { UserChannel } from '../email.js';
16
16
  import type {
17
17
  AgentSearchScope,
18
18
  ConversationVisibility,
19
+ InitialToolCall,
19
20
  InteractionExecutionConfiguration,
20
21
  InteractionRef,
21
22
  RunSource,
@@ -173,6 +174,15 @@ export interface AgentRunBase<TData = Record<string, unknown>, TProperties = Rec
173
174
  /** Tools configured for this run (+/- syntax supported) */
174
175
  tool_names?: string[];
175
176
 
177
+ /** Builtin system skills activated before the first model turn. */
178
+ initial_skills?: string[];
179
+
180
+ /** Ordered, bounded hydration/read calls executed before the first model turn. */
181
+ initial_tool_calls?: InitialToolCall[];
182
+
183
+ /** Hard denylist of tool names: never exposed to the model, refused at execution time. */
184
+ excluded_tools?: string[];
185
+
176
186
  /** Scoped collection (if any) */
177
187
  collection_id?: string;
178
188
 
@@ -547,6 +557,25 @@ export interface AgentArtifactUrlResponse {
547
557
  path: string;
548
558
  }
549
559
 
560
+ /** Text content and concurrency token for an agent artifact. */
561
+ export interface AgentArtifactContentResponse {
562
+ path: string;
563
+ content: string;
564
+ generation: string;
565
+ }
566
+
567
+ /** Conditional text update for an agent artifact. */
568
+ export interface UpdateAgentArtifactContentPayload {
569
+ content: string;
570
+ generation: string;
571
+ }
572
+
573
+ /** Result of a conditional agent artifact update. */
574
+ export interface UpdateAgentArtifactContentResponse {
575
+ path: string;
576
+ generation: string;
577
+ }
578
+
550
579
  /**
551
580
  * Telemetry ingestion payload for an agent run.
552
581
  */
@@ -0,0 +1,17 @@
1
+ import Ajv from 'ajv';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { ContentTypeEditingPolicySchema } from './store.js';
4
+
5
+ const validate = new Ajv.default({ allErrors: true, strict: false }).compile(ContentTypeEditingPolicySchema);
6
+
7
+ describe('ContentTypeEditingPolicySchema', () => {
8
+ it('accepts an omitted or configured interaction', () => {
9
+ expect(validate({})).toBe(true);
10
+ expect(validate({ interaction: 'sys:GeneralAgent' })).toBe(true);
11
+ });
12
+
13
+ it('rejects unknown fields and non-string interactions', () => {
14
+ expect(validate({ interaction: 42 })).toBe(false);
15
+ expect(validate({ interaction: 'sys:GeneralAgent', tools: [] })).toBe(false);
16
+ });
17
+ });
@@ -206,6 +206,9 @@ export interface ConversationState {
206
206
  */
207
207
  skill_instructions_delivered?: string[];
208
208
 
209
+ /** Stable ids of initialization tool calls completed before the first model turn. */
210
+ initialization_call_ids?: string[];
211
+
209
212
  /**
210
213
  * Denylist of MCP tool-collection ids deactivated for this conversation.
211
214
  * `undefined`/empty means all installed/connected MCP collections are active.
@@ -1034,6 +1034,26 @@ export interface ContentTypeIntakePolicy {
1034
1034
  default_view?: 'auto' | 'text' | 'pdf' | 'image' | 'properties';
1035
1035
  }
1036
1036
 
1037
+ /** Per-content-type policy for collaborative document editing. */
1038
+ export interface ContentTypeEditingPolicy {
1039
+ /** Agent interaction used for new document-editing sessions. Defaults to sys:GeneralAgent. */
1040
+ interaction?: string;
1041
+ }
1042
+
1043
+ export const ContentTypeEditingPolicySchema: JSONSchemaType<ContentTypeEditingPolicy> = {
1044
+ type: 'object',
1045
+ description: 'Per-content-type policy for collaborative document editing.',
1046
+ required: [],
1047
+ additionalProperties: false,
1048
+ properties: {
1049
+ interaction: {
1050
+ type: 'string',
1051
+ description: 'Agent interaction used for new document-editing sessions. Omit to use sys:GeneralAgent.',
1052
+ nullable: true,
1053
+ },
1054
+ },
1055
+ };
1056
+
1037
1057
  /** Reusable sub-schema for IntakePageScope ('all' | 'located'). */
1038
1058
  const IntakePageScopeSchema = {
1039
1059
  type: 'string',
@@ -1494,6 +1514,7 @@ export interface ContentObjectTypeItem extends BaseObject {
1494
1514
  status?: ContentObjectTypeStatus;
1495
1515
  is_chunkable?: boolean;
1496
1516
  intake?: ContentTypeIntakePolicy;
1517
+ editing?: ContentTypeEditingPolicy;
1497
1518
  /**
1498
1519
  * This is only included in ContentObjectTypeItem if explicitly requested
1499
1520
  * It is always included in ContentObjectType
@@ -1522,6 +1543,7 @@ export type InCodeTypeDefinition = Pick<
1522
1543
  | 'strict_mode'
1523
1544
  | 'status'
1524
1545
  | 'intake'
1546
+ | 'editing'
1525
1547
  >;
1526
1548
  export interface ContentObjectTypeCatalogEntry extends InCodeTypeDefinition {
1527
1549
  updated_by?: string;
@@ -1,10 +1,12 @@
1
1
  import type { ExecutionTokenUsage, HttpTimeoutOptions, ModelOptions } from '@llumiverse/common';
2
2
  import type {
3
+ AgentResourceReference,
3
4
  ConversationVisibility,
4
5
  InteractionExecutionConfiguration,
5
6
  InteractionRef,
6
7
  UserChannel,
7
8
  } from '../interaction.js';
9
+ import { normalizeAgentResources } from '../interaction.js';
8
10
  import type { JSONObject, JSONValue } from '../json.js';
9
11
  import type { JSONSchema } from '../json-schema.js';
10
12
  import type { SupportedEmbeddingTypes } from '../project.js';
@@ -770,6 +772,8 @@ export interface AgentMessageDetails extends Record<string, unknown> {
770
772
  outputFiles?: string[];
771
773
  files?: ConversationFile[] | string[];
772
774
  plan?: PlanTask[];
775
+ /** Deep-linkable references to resources a tool created/updated/deleted (see AgentResourceReference). */
776
+ resources?: AgentResourceReference[];
773
777
  streaming_id?: string;
774
778
  streaming_id_scope?: 'workflow_run' | 'workstream';
775
779
  chunk_index?: number;
@@ -846,6 +850,11 @@ export function isToolCallMessage(msg: AgentMessage): msg is AgentMessage & { de
846
850
  );
847
851
  }
848
852
 
853
+ /** Extract the normalized resource references carried on a message's details, if any. */
854
+ export function getResourcesFromMessage(msg: AgentMessage): AgentResourceReference[] {
855
+ return normalizeAgentResources((msg.details as AgentMessageDetails | undefined)?.resources);
856
+ }
857
+
849
858
  export function isDocumentEventMessage(msg: AgentMessage): msg is AgentMessage & { details: DocumentEventDetails } {
850
859
  const details = msg.details as Record<string, unknown> | undefined;
851
860
  return (