@tangle-network/agent-app 0.47.6 → 0.47.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.
@@ -29,6 +29,8 @@ export interface DurableWorkspaceKeyRecord {
29
29
  sourceKeyFingerprint: string;
30
30
  /** The persisted name used to recover a remote create after a crash. Null only for pre-name rows. */
31
31
  name: string | null;
32
+ /** The persisted retry identity for the remote create. Absent on legacy rows without a persisted create identity. */
33
+ idempotencyKey?: string | null;
32
34
  keyId: string;
33
35
  keyEncrypted: string;
34
36
  budgetUsd: number;
@@ -48,9 +50,21 @@ type DurableWorkspaceKeyCreateResult = Awaited<ReturnType<KeyProvisioner['create
48
50
  budgetRemaining?: number;
49
51
  expiresAt?: string | null;
50
52
  };
53
+ /** The exact request identity that must be reused when recovering a create. */
54
+ export interface DurableWorkspaceKeyCreateInput {
55
+ name: string;
56
+ product: string;
57
+ budgetUsd: number;
58
+ expiresAt: string;
59
+ /** Stable across process restarts for one persisted provisioning row. */
60
+ idempotencyKey: string;
61
+ }
51
62
  /** The remote operations required by the durable manager. */
52
63
  export interface DurableWorkspaceKeyProvisioner {
53
- createKey(input: Parameters<KeyProvisioner['createKey']>[0]): Promise<DurableWorkspaceKeyCreateResult>;
64
+ /** True only when replay returns the original child for the persisted request identity. */
65
+ supportsIdempotentCreate?: true;
66
+ /** Create one child key. Non-idempotent providers recover through stable-name discovery only. */
67
+ createKey(input: DurableWorkspaceKeyCreateInput): Promise<DurableWorkspaceKeyCreateResult>;
54
68
  getKey(id: string): Promise<{
55
69
  budgetUsd?: number | null;
56
70
  budgetSpent?: number;
@@ -66,6 +80,22 @@ export interface DurableWorkspaceKeyProvisioner {
66
80
  id: string;
67
81
  }>>;
68
82
  }
83
+ /** Optional compare-and-set lifecycle writes for stores that support fencing. */
84
+ export interface DurableWorkspaceKeyConditionalWrites {
85
+ /** Return false when the row was no longer provisioning. */
86
+ markProvisioningRemote(input: {
87
+ id: string;
88
+ keyId: string;
89
+ }): Promise<boolean>;
90
+ /** Return false when the row was no longer provisioning. */
91
+ markActive(input: {
92
+ id: string;
93
+ keyId: string;
94
+ keyEncrypted: string;
95
+ expiresAt: Date;
96
+ budgetUsd: number;
97
+ }): Promise<boolean>;
98
+ }
69
99
  /** Persistence operations for identity-bound key lifecycle state. */
70
100
  export interface DurableWorkspaceKeyStore {
71
101
  /** Return the active row for this exact product scope. */
@@ -87,7 +117,12 @@ export interface DurableWorkspaceKeyStore {
87
117
  expiresAt: Date;
88
118
  budgetUsd: number;
89
119
  }): Promise<void>;
90
- /** Keep a failed cleanup visible and schedule a later retry. */
120
+ /**
121
+ * Optional fenced writes. The manager uses false to compensate a stale
122
+ * creator. Stores without this field retain the pre-fence behavior.
123
+ */
124
+ conditionalWrites?: DurableWorkspaceKeyConditionalWrites;
125
+ /** Keep a failed cleanup visible and schedule a later retry. Terminal rows are immutable. */
91
126
  markRevocationPending(input: {
92
127
  id: string;
93
128
  error?: string | null;
@@ -139,13 +174,22 @@ export interface DurableWorkspaceKeyManager {
139
174
  }): Promise<WorkspaceRuntimeKey>;
140
175
  /** Read usage without returning the child secret. */
141
176
  getUsage(identity: WorkspaceKeyIdentity): Promise<WorkspaceKeyUsage | null>;
142
- /** Retry due cleanup rows. A supplied owner/workspace limits the retry to its scope. */
143
- retryPendingRevocations(scope?: Pick<WorkspaceKeyIdentity, 'ownerUserId' | 'workspaceId'>): Promise<number>;
177
+ /**
178
+ * Retry due cleanup rows. A supplied owner/workspace limits the retry to its
179
+ * scope. Empty provisioning rows also require the full identity so a retry
180
+ * can use the original source binding safely.
181
+ */
182
+ retryPendingRevocations(scope?: Pick<WorkspaceKeyIdentity, 'ownerUserId' | 'workspaceId'>, identity?: WorkspaceKeyIdentity): Promise<number>;
144
183
  }
145
184
  /** Configuration for {@link createIdentityBoundWorkspaceKeyManager}. */
146
185
  export interface DurableWorkspaceKeyManagerOptions {
147
186
  store: DurableWorkspaceKeyStore;
148
187
  provisioner: DurableWorkspaceKeyProvisioner;
188
+ /**
189
+ * Control-plane client for historical get/revoke/list operations. Use this
190
+ * when the source credential can rotate or disappear. It never mints keys.
191
+ */
192
+ recoveryProvisioner?: Pick<DurableWorkspaceKeyProvisioner, 'getKey' | 'revokeKey' | 'findCreatedKeys'>;
149
193
  crypto: KeyCrypto;
150
194
  /** Product partition. Products must use separate values. */
151
195
  product: WorkspaceKeyProduct;
@@ -239,4 +239,4 @@ export interface PlatformBalanceManager<Plan extends string> {
239
239
  export declare function createPlatformBalanceManager<Plan extends string>(opts: PlatformBalanceManagerOptions<Plan>): PlatformBalanceManager<Plan>;
240
240
  /** Create a workspace key manager that handles key provisioning and budget tracking */
241
241
  export declare function createWorkspaceKeyManager(opts: WorkspaceKeyManagerOptions): WorkspaceKeyManager;
242
- export { createIdentityBoundWorkspaceKeyManager, type DurableWorkspaceKeyManager, type DurableWorkspaceKeyManagerOptions, type DurableWorkspaceKeyProvisioner, type DurableWorkspaceKeyProvisioningRecord, type DurableWorkspaceKeyRecord, type DurableWorkspaceKeyScope, type DurableWorkspaceKeyStore, type WorkspaceKeyIdentity, type WorkspaceKeyProduct, type WorkspaceKeyStatus, type WorkspaceKeyUsage, type WorkspaceRuntimeKey, } from './identity-bound';
242
+ export { createIdentityBoundWorkspaceKeyManager, type DurableWorkspaceKeyManager, type DurableWorkspaceKeyManagerOptions, type DurableWorkspaceKeyCreateInput, type DurableWorkspaceKeyConditionalWrites, type DurableWorkspaceKeyProvisioner, type DurableWorkspaceKeyProvisioningRecord, type DurableWorkspaceKeyRecord, type DurableWorkspaceKeyScope, type DurableWorkspaceKeyStore, type WorkspaceKeyIdentity, type WorkspaceKeyProduct, type WorkspaceKeyStatus, type WorkspaceKeyUsage, type WorkspaceRuntimeKey, } from './identity-bound';
@@ -3,7 +3,7 @@ import {
3
3
  createPlatformBalanceManager,
4
4
  createTcloudKeyProvisioner,
5
5
  createWorkspaceKeyManager
6
- } from "../chunk-TS2ZIB53.js";
6
+ } from "../chunk-4ZJYNI53.js";
7
7
  export {
8
8
  createIdentityBoundWorkspaceKeyManager,
9
9
  createPlatformBalanceManager,
@@ -1148,6 +1148,7 @@ function createProtectedRuntimeChatProducer(options) {
1148
1148
  }
1149
1149
  });
1150
1150
  let completed = false;
1151
+ let streamedText = "";
1151
1152
  for await (const event of streamAgentTurn(
1152
1153
  { kind: "executor", factory, profile },
1153
1154
  { prompt: options.prompt },
@@ -1157,6 +1158,7 @@ function createProtectedRuntimeChatProducer(options) {
1157
1158
  timeoutMs: Math.max(1, options.grant.deadlineAtMs - Date.now())
1158
1159
  }
1159
1160
  )) {
1161
+ if (event.type === "text_delta") streamedText += event.text;
1160
1162
  if (event.type === "text_delta" || event.type === "reasoning_delta") {
1161
1163
  await emit({ type: "message.part.updated", data: {
1162
1164
  part: { id: event.type, type: event.type === "text_delta" ? "text" : "reasoning" },
@@ -1165,6 +1167,17 @@ function createProtectedRuntimeChatProducer(options) {
1165
1167
  }
1166
1168
  if (event.type === "final") {
1167
1169
  if (event.status !== "completed") throw new Error(`Protected execution ${event.status}`);
1170
+ if (event.text !== void 0) {
1171
+ if (!event.text.startsWith(streamedText)) {
1172
+ throw new Error("Protected execution revised already streamed text");
1173
+ }
1174
+ const suffix = event.text.slice(streamedText.length);
1175
+ if (suffix) await emit({ type: "message.part.updated", data: {
1176
+ part: { id: "text_delta", type: "text" },
1177
+ delta: suffix
1178
+ } });
1179
+ streamedText = event.text;
1180
+ }
1168
1181
  completed = true;
1169
1182
  await emit({ type: "result", data: { finalText: event.text } });
1170
1183
  }