@ixo/oracle-runtime-workers 0.30.0 → 0.32.0
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 +7 -5
- package/src/attachments/channel-links.ts +135 -0
- package/src/attachments/channel.ts +203 -0
- package/src/attachments/download.ts +23 -6
- package/src/attachments/index.ts +23 -0
- package/src/attachments/pipeline.ts +120 -42
- package/src/attachments/retention.ts +11 -3
- package/src/attachments/sanitize.ts +20 -8
- package/src/attachments/types.ts +7 -0
- package/src/attachments/view.ts +24 -7
- package/src/channels/contract.ts +69 -0
- package/src/channels/turns.ts +23 -1
- package/src/core/main-agent-types.ts +2 -0
- package/src/core/middlewares/tool-repetition-guard.ts +6 -3
- package/src/core/middlewares/turn-boundary.ts +6 -1
- package/src/core/runtime-context.ts +3 -0
- package/src/core/tool-not-run.ts +30 -0
- package/src/core/wrap-plugin-tool.ts +9 -1
- package/src/delivery/plan.ts +3 -1
- package/src/do/contracts.ts +3 -0
- package/src/do/turn-attachments.ts +103 -0
- package/src/do/user-oracle-do.ts +220 -57
- package/src/hub-actions/chain-tx-refusals.ts +217 -0
- package/src/hub-actions/client.ts +170 -26
- package/src/hub-actions/hub-text.ts +82 -0
- package/src/hub-actions/request.ts +39 -29
- package/src/hub-actions/store.ts +5 -1
- package/src/hub-actions/transfer.ts +99 -32
- package/src/index.ts +1 -0
- package/src/plugin-api/index.ts +1 -0
- package/src/plugin-api/types.ts +102 -20
- package/src/plugins/attachments/view-attachment-tool.ts +7 -3
- package/src/plugins/hub-actions/chain-tx-catalog.ts +1239 -0
- package/src/plugins/hub-actions/hub-actions.plugin.ts +490 -232
- package/src/plugins/ixo-chain/blocksync.ts +6 -2
- package/src/plugins/ixo-chain/http.ts +16 -8
- package/src/plugins/ixo-chain/ixo-chain.plugin.ts +1 -1
- package/src/plugins/ixo-chain/kinds/chain/index.ts +2 -0
- package/src/plugins/ixo-chain/kinds/chain/validators.ts +151 -0
- package/src/plugins/ixo-chain/rest.ts +7 -1
- package/src/plugins/yoma/catalog.ts +780 -0
- package/src/plugins/yoma/clef.ts +98 -0
- package/src/plugins/yoma/drafts.ts +339 -0
- package/src/plugins/yoma/engine.ts +978 -0
- package/src/plugins/yoma/index.ts +13 -0
- package/src/plugins/yoma/judge.ts +358 -0
- package/src/plugins/yoma/permission.ts +62 -0
- package/src/plugins/yoma/reads.ts +195 -0
- package/src/plugins/yoma/submission.ts +531 -0
- package/src/plugins/yoma/text.ts +16 -0
- package/src/plugins/yoma/work.ts +190 -0
- package/src/plugins/yoma/yoma.plugin.ts +2171 -0
- package/src/sqlite/serialization.ts +2 -0
package/src/hub-actions/store.ts
CHANGED
|
@@ -42,13 +42,17 @@ const HUB_RETENTION_SECONDS = 30 * 24 * 60 * 60;
|
|
|
42
42
|
/**
|
|
43
43
|
* A refusal the model can act on: a cap reached, a request that expired, or
|
|
44
44
|
* an operation the owner's own state rules out (an unknown connection, an
|
|
45
|
-
* email whose earlier send is unconfirmed: `priorActionId`).
|
|
45
|
+
* email whose earlier send is unconfirmed: `priorActionId`). A refusal
|
|
46
|
+
* Auth Hub answered carries its HTTP status (`httpStatus`), so a caller can
|
|
47
|
+
* tell a 429 or 503, which pass with time, from a deterministic refusal
|
|
48
|
+
* without reading the words.
|
|
46
49
|
*/
|
|
47
50
|
export class HubActionRefused extends Error {
|
|
48
51
|
constructor(
|
|
49
52
|
readonly kind: 'limit' | 'expired' | 'refused',
|
|
50
53
|
message: string,
|
|
51
54
|
readonly priorActionId?: string,
|
|
55
|
+
readonly httpStatus?: number,
|
|
52
56
|
) {
|
|
53
57
|
super(message);
|
|
54
58
|
this.name = 'HubActionRefused';
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
parseChainTxRefusal,
|
|
3
|
+
type ActionOperationV1,
|
|
4
|
+
type ActionReceiptV1,
|
|
5
|
+
type OptionsToken,
|
|
5
6
|
} from '@ixo/action-protocol';
|
|
7
|
+
import { chainTxRefusalWords, wordableRefusal } from './chain-tx-refusals';
|
|
6
8
|
import type { ChainTxMessageInput } from '../plugin-api/types';
|
|
9
|
+
import { quoteHubText } from './hub-text';
|
|
7
10
|
import type { ChainTxHostMessage } from './request';
|
|
8
11
|
import { HubActionRefused } from './store';
|
|
9
12
|
|
|
@@ -90,24 +93,67 @@ const IXO_TOKEN: TransferToken = {
|
|
|
90
93
|
};
|
|
91
94
|
|
|
92
95
|
/**
|
|
93
|
-
* A chain transaction's
|
|
96
|
+
* A chain transaction's amounts in base units; messages without one pass
|
|
94
97
|
* unchanged. Each bank step names a display `amount` of a token from the
|
|
95
98
|
* owner's list (`denom`, absent = uixo): the token must be listed, the
|
|
96
99
|
* amount converts with its listed decimals (`toBaseUnits`: a plain decimal,
|
|
97
100
|
* no more digits after the point than the decimals, above zero; an
|
|
98
101
|
* unverified token lists 0: base units), and the bank steps of one token
|
|
99
|
-
* together stay within its listed balance.
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
+
* together stay within its listed balance. Each stake step (stake, unstake,
|
|
103
|
+
* move stake) names a display `amount` of IXO, converted with IXO's 6
|
|
104
|
+
* decimals; what a stake takes from the wallet counts against the listed
|
|
105
|
+
* IXO balance together with the IXO bank steps, when the list has IXO
|
|
106
|
+
* (Auth Hub checks every balance again before the card is made). `tokens`
|
|
107
|
+
* is the owner's list (hub_action_options `transfer.tokens`), null when the
|
|
108
|
+
* Hub listed none; the caller reads it only when there is a bank or stake
|
|
109
|
+
* step.
|
|
102
110
|
*/
|
|
103
|
-
export function
|
|
111
|
+
export function chainTxAmountsInBaseUnits(
|
|
104
112
|
messages: readonly ChainTxMessageInput[],
|
|
105
113
|
tokens: readonly OptionsToken[] | null,
|
|
106
114
|
): ChainTxHostMessage[] {
|
|
107
115
|
const spent = new Map<string, bigint>();
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
/** The bank and stake steps of one listed token together, within its listed balance. */
|
|
117
|
+
const spend = (
|
|
118
|
+
at: string,
|
|
119
|
+
token: OptionsToken,
|
|
120
|
+
amount: bigint,
|
|
121
|
+
what: string,
|
|
122
|
+
) => {
|
|
123
|
+
const total = (spent.get(token.denom) ?? 0n) + amount;
|
|
124
|
+
spent.set(token.denom, total);
|
|
125
|
+
if (total > BigInt(token.balanceBaseUnits))
|
|
126
|
+
throw new HubActionRefused(
|
|
127
|
+
'refused',
|
|
128
|
+
`${at}.amount: the owner holds ${describeAmount(token.balanceBaseUnits, token)}, less than ${total === amount ? what : 'what the steps of this transaction take of it together'}.`,
|
|
129
|
+
);
|
|
130
|
+
};
|
|
131
|
+
const converted = (at: string, amount: string, decimals: number) => {
|
|
132
|
+
try {
|
|
133
|
+
return toBaseUnits(amount, decimals);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof HubActionRefused)
|
|
136
|
+
throw new HubActionRefused('refused', `${at}.amount: ${error.message}`);
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
return messages.map((message, index): ChainTxHostMessage => {
|
|
110
141
|
const at = `messages[${index}]`;
|
|
142
|
+
if (
|
|
143
|
+
message.type === 'cosmos.staking.delegate' ||
|
|
144
|
+
message.type === 'cosmos.staking.undelegate' ||
|
|
145
|
+
message.type === 'cosmos.staking.redelegate'
|
|
146
|
+
) {
|
|
147
|
+
const { amount: display, ...rest } = message;
|
|
148
|
+
const amount = converted(at, display, IXO_TOKEN.decimals);
|
|
149
|
+
// Only a stake takes IXO from the wallet: unstaking and moving stake
|
|
150
|
+
// work on what is already staked.
|
|
151
|
+
const ixo = tokens?.find((item) => item.denom === IXO_TOKEN.denom);
|
|
152
|
+
if (message.type === 'cosmos.staking.delegate' && ixo)
|
|
153
|
+
spend(at, ixo, amount, 'this stake');
|
|
154
|
+
return { ...rest, amountBaseUnits: amount.toString() };
|
|
155
|
+
}
|
|
156
|
+
if (message.type !== 'cosmos.bank.send') return message;
|
|
111
157
|
if (!tokens?.length)
|
|
112
158
|
throw new HubActionRefused(
|
|
113
159
|
'refused',
|
|
@@ -123,21 +169,8 @@ export function bankStepsInBaseUnits(
|
|
|
123
169
|
.slice(0, 10)
|
|
124
170
|
.join(', ')}).`,
|
|
125
171
|
);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
amount = toBaseUnits(message.amount, token.decimals);
|
|
129
|
-
} catch (error) {
|
|
130
|
-
if (error instanceof HubActionRefused)
|
|
131
|
-
throw new HubActionRefused('refused', `${at}.amount: ${error.message}`);
|
|
132
|
-
throw error;
|
|
133
|
-
}
|
|
134
|
-
const total = (spent.get(token.denom) ?? 0n) + amount;
|
|
135
|
-
spent.set(token.denom, total);
|
|
136
|
-
if (total > BigInt(token.balanceBaseUnits))
|
|
137
|
-
throw new HubActionRefused(
|
|
138
|
-
'refused',
|
|
139
|
-
`${at}.amount: the owner holds ${describeAmount(token.balanceBaseUnits, token)}, less than ${total === amount ? 'this send' : 'the bank steps of this token in this transaction'}.`,
|
|
140
|
-
);
|
|
172
|
+
const amount = converted(at, message.amount, token.decimals);
|
|
173
|
+
spend(at, token, amount, 'this send');
|
|
141
174
|
return {
|
|
142
175
|
type: 'cosmos.bank.send',
|
|
143
176
|
toAddress: message.toAddress,
|
|
@@ -279,11 +312,14 @@ function hubErrorBody(
|
|
|
279
312
|
return null;
|
|
280
313
|
const reason =
|
|
281
314
|
'reason' in body && typeof body.reason === 'string' && body.reason.trim()
|
|
282
|
-
? body.reason.trim()
|
|
315
|
+
? body.reason.trim()
|
|
283
316
|
: undefined;
|
|
284
317
|
return reason ? { error, reason } : { error };
|
|
285
318
|
}
|
|
286
319
|
|
|
320
|
+
/** The longest part of a Hub refusal's `reason` the model is given. */
|
|
321
|
+
const HUB_REASON_MAX = 200;
|
|
322
|
+
|
|
287
323
|
/**
|
|
288
324
|
* A Hub refusal of a prepare (`{error, reason?}` with status 400, 409 or
|
|
289
325
|
* 503, or any 404 or 429) as a refusal the model can relay, or null when
|
|
@@ -295,7 +331,8 @@ function hubErrorBody(
|
|
|
295
331
|
* try again later;
|
|
296
332
|
* - 400 `simulation_failed`, `fee_above_ceiling`, `insufficient_funds`,
|
|
297
333
|
* `not_authorized`, `operation_not_registered`: the transfer or
|
|
298
|
-
* transaction as asked cannot go ahead (with the Hub's reason
|
|
334
|
+
* transaction as asked cannot go ahead (with the Hub's reason, quoted and
|
|
335
|
+
* labelled as data, see `quoteHubText`);
|
|
299
336
|
* - 409 `sequence_mismatch`, 503 `transfer_unavailable`: temporary, try
|
|
300
337
|
* again shortly;
|
|
301
338
|
* - any other 409: the account may not use this operation (deterministic,
|
|
@@ -308,24 +345,54 @@ export function hubPrepareRefusal(
|
|
|
308
345
|
): HubActionRefused | null {
|
|
309
346
|
const parsed = hubErrorBody(body);
|
|
310
347
|
const unfixable = unfixableRefusal(status, parsed, subject);
|
|
311
|
-
if (unfixable)
|
|
348
|
+
if (unfixable)
|
|
349
|
+
return new HubActionRefused('refused', unfixable, undefined, status);
|
|
312
350
|
if (!parsed) return null;
|
|
313
|
-
|
|
351
|
+
// A chain transaction Auth Hub would not make from what it read on chain,
|
|
352
|
+
// or whose simulation named one message: a fixed code, in the runtime's
|
|
353
|
+
// own words (the reason text is not passed on). Without a code, the
|
|
354
|
+
// reason is passed on quoted, as below.
|
|
355
|
+
const coded =
|
|
356
|
+
status === 400 &&
|
|
357
|
+
subject === 'transaction' &&
|
|
358
|
+
(parsed.error === 'operation_not_registered' ||
|
|
359
|
+
parsed.error === 'simulation_failed')
|
|
360
|
+
? wordableRefusal(parseChainTxRefusal(parsed.reason))
|
|
361
|
+
: null;
|
|
362
|
+
if (coded)
|
|
363
|
+
return new HubActionRefused(
|
|
364
|
+
'refused',
|
|
365
|
+
chainTxRefusalWords(coded),
|
|
366
|
+
undefined,
|
|
367
|
+
status,
|
|
368
|
+
);
|
|
369
|
+
const reason = parsed.reason
|
|
370
|
+
? quoteHubText('reason', parsed.reason, HUB_REASON_MAX)
|
|
371
|
+
: '';
|
|
314
372
|
const words =
|
|
315
373
|
status === 400 && Object.hasOwn(HUB_PREPARE_REFUSALS, parsed.error)
|
|
316
374
|
? HUB_PREPARE_REFUSALS[parsed.error]
|
|
317
375
|
: undefined;
|
|
318
376
|
if (words)
|
|
319
|
-
return new HubActionRefused(
|
|
377
|
+
return new HubActionRefused(
|
|
378
|
+
'refused',
|
|
379
|
+
`${words(subject)}.${reason ? ` ${reason}.` : ''}`,
|
|
380
|
+
undefined,
|
|
381
|
+
status,
|
|
382
|
+
);
|
|
320
383
|
if (HUB_TRANSIENT_CODES[status]?.includes(parsed.error))
|
|
321
384
|
return new HubActionRefused(
|
|
322
385
|
'refused',
|
|
323
386
|
`Auth Hub is temporarily unavailable for this (${parsed.error}); try again shortly.`,
|
|
387
|
+
undefined,
|
|
388
|
+
status,
|
|
324
389
|
);
|
|
325
390
|
if (status === 409)
|
|
326
391
|
return new HubActionRefused(
|
|
327
392
|
'refused',
|
|
328
|
-
`This operation is not available for this account (${parsed.error}${
|
|
393
|
+
`This operation is not available for this account (${parsed.error}).${reason ? ` ${reason}.` : ''}`,
|
|
394
|
+
undefined,
|
|
395
|
+
status,
|
|
329
396
|
);
|
|
330
397
|
return null;
|
|
331
398
|
}
|
package/src/index.ts
CHANGED
|
@@ -45,6 +45,7 @@ export * from './plugin-api';
|
|
|
45
45
|
export * from './plugins';
|
|
46
46
|
export * from './do/contracts';
|
|
47
47
|
export type { OwnerStore } from './owner-store/types';
|
|
48
|
+
export type { ChannelAttachment } from './channels/contract';
|
|
48
49
|
export { MigratingOwnerStore } from './owner-store/migrating-store';
|
|
49
50
|
export {
|
|
50
51
|
IxoVfsOwnerStore,
|
package/src/plugin-api/index.ts
CHANGED
package/src/plugin-api/types.ts
CHANGED
|
@@ -18,7 +18,12 @@ import type { BaseMessage } from '@langchain/core/messages';
|
|
|
18
18
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
19
19
|
import type { UserPreferences } from '../core/state';
|
|
20
20
|
import type { AttachmentViewSurface } from '../attachments/view';
|
|
21
|
+
import type { ChannelAttachment } from '../channels/contract';
|
|
21
22
|
import type { DeliveryConfig } from '../delivery/profile';
|
|
23
|
+
import type {
|
|
24
|
+
HubOperationStatus,
|
|
25
|
+
HubReviewStatus,
|
|
26
|
+
} from '../hub-actions/client';
|
|
22
27
|
import type {
|
|
23
28
|
ActionOperationV1,
|
|
24
29
|
ActionReferenceV1,
|
|
@@ -27,13 +32,40 @@ import type {
|
|
|
27
32
|
ChainTxMessage,
|
|
28
33
|
} from '@ixo/action-protocol';
|
|
29
34
|
|
|
35
|
+
/** `Omit` applied to each member of a union (plain `Omit` merges them). */
|
|
36
|
+
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown
|
|
37
|
+
? Omit<T, K>
|
|
38
|
+
: never;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The owner's own identity in chain-transaction messages, which the host
|
|
42
|
+
* fills and the model never names: the filer's or disputer's `agentDid`
|
|
43
|
+
* (claims, reservations, disputes), an evaluation's `agentDid` and
|
|
44
|
+
* `agentAddress`, a claim permission's `creatorDid`, an entity update's
|
|
45
|
+
* `controllerDid` and a new entity's `ownerDid`: always `did:ixo:<signer>`,
|
|
46
|
+
* or the signer for an address.
|
|
47
|
+
*/
|
|
48
|
+
export type ChainTxOwnerField =
|
|
49
|
+
| 'agentDid'
|
|
50
|
+
| 'agentAddress'
|
|
51
|
+
| 'creatorDid'
|
|
52
|
+
| 'controllerDid'
|
|
53
|
+
| 'ownerDid';
|
|
54
|
+
|
|
55
|
+
/** The stake steps: their amount is IXO, written in display units. */
|
|
56
|
+
export type ChainTxStakeType =
|
|
57
|
+
| 'cosmos.staking.delegate'
|
|
58
|
+
| 'cosmos.staking.undelegate'
|
|
59
|
+
| 'cosmos.staking.redelegate';
|
|
60
|
+
|
|
30
61
|
/**
|
|
31
62
|
* A chain-transaction message as the model writes it: the protocol's
|
|
32
|
-
* message without the owner's identity, which the
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
63
|
+
* message without the owner's identity (`ChainTxOwnerField`), which the
|
|
64
|
+
* host fills. A bank step names a display `amount` of a token from the
|
|
65
|
+
* owner's list (`denom`, absent = uixo); a stake step a display `amount` of
|
|
66
|
+
* IXO. The host converts both to the protocol's `amountBaseUnits` (the
|
|
67
|
+
* listed decimals; 6 for IXO). Every other amount (impact tokens, a
|
|
68
|
+
* collection's payments) is already in the protocol's units.
|
|
37
69
|
*/
|
|
38
70
|
export type ChainTxMessageInput =
|
|
39
71
|
| {
|
|
@@ -43,11 +75,16 @@ export type ChainTxMessageInput =
|
|
|
43
75
|
amount: string;
|
|
44
76
|
denom?: string;
|
|
45
77
|
}
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
| (DistributiveOmit<
|
|
79
|
+
Extract<ChainTxMessage, { type: ChainTxStakeType }>,
|
|
80
|
+
'amountBaseUnits'
|
|
81
|
+
> & {
|
|
82
|
+
/** A plain decimal in IXO ("100" or "0.5"). */
|
|
83
|
+
amount: string;
|
|
84
|
+
})
|
|
85
|
+
| DistributiveOmit<
|
|
86
|
+
Exclude<ChainTxMessage, { type: 'cosmos.bank.send' | ChainTxStakeType }>,
|
|
87
|
+
ChainTxOwnerField
|
|
51
88
|
>;
|
|
52
89
|
|
|
53
90
|
/**
|
|
@@ -551,6 +588,25 @@ export type SessionSurface =
|
|
|
551
588
|
| { kind: 'stream' }
|
|
552
589
|
| { kind: 'chat'; surface: string; label: string };
|
|
553
590
|
|
|
591
|
+
/** What `ctx.hubActions.status` reads. */
|
|
592
|
+
export interface HubActionStatusRead {
|
|
593
|
+
/** False when this owner object holds no action with this id (Auth Hub was not asked). */
|
|
594
|
+
held: boolean;
|
|
595
|
+
/**
|
|
596
|
+
* Auth Hub's review status (`prepared`, `authorized`, `declined`,
|
|
597
|
+
* `expired`, …) and operation status, each one the protocol lists or
|
|
598
|
+
* `unknown` for anything else Auth Hub answered; null when not held.
|
|
599
|
+
* With no outcome yet they tell an action still waiting from one whose
|
|
600
|
+
* review lapsed.
|
|
601
|
+
*/
|
|
602
|
+
reviewStatus: HubReviewStatus | null;
|
|
603
|
+
operationStatus: HubOperationStatus | null;
|
|
604
|
+
/** The latest authenticated outcome; null when there is none (yet). */
|
|
605
|
+
outcome: ActionOutcomeV1 | null;
|
|
606
|
+
/** For a bank-send receipt, the owner-facing line. */
|
|
607
|
+
summary: string | null;
|
|
608
|
+
}
|
|
609
|
+
|
|
554
610
|
export interface RuntimeContext<TConfig = MergedConfig> {
|
|
555
611
|
/** Authenticated user identity (validated by core auth middleware). */
|
|
556
612
|
user: {
|
|
@@ -575,6 +631,14 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
575
631
|
provider: string;
|
|
576
632
|
bindingId: string;
|
|
577
633
|
bindingRevision: number;
|
|
634
|
+
/**
|
|
635
|
+
* Files the person sent with this turn's message (a WhatsApp photo,
|
|
636
|
+
* video, document or audio file), as the channel gateway serves them:
|
|
637
|
+
* a capability `url` plus the `sha256` of its bytes. Absent when the
|
|
638
|
+
* message carried none. The model also sees them through the
|
|
639
|
+
* attachment pipeline; this is the raw list for tools that keep them.
|
|
640
|
+
*/
|
|
641
|
+
attachments?: readonly ChannelAttachment[];
|
|
578
642
|
};
|
|
579
643
|
roomId?: string;
|
|
580
644
|
/**
|
|
@@ -780,7 +844,13 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
780
844
|
|
|
781
845
|
/** Host-owned action coordinator. It accepts only runtime-derived channel context. */
|
|
782
846
|
hubActions?: {
|
|
783
|
-
|
|
847
|
+
/**
|
|
848
|
+
* The Hub's capabilities for this oracle account (cached 60 s).
|
|
849
|
+
* `turn`: a read on a turn's critical path (a tool list): a short
|
|
850
|
+
* timeout, no new read within 30 s of a failed one, and the last
|
|
851
|
+
* capabilities read while reads fail.
|
|
852
|
+
*/
|
|
853
|
+
capabilities(opts?: { turn?: boolean }): Promise<ActionCapabilitiesV1>;
|
|
784
854
|
options(input: {
|
|
785
855
|
ownerDid: string;
|
|
786
856
|
provider: string;
|
|
@@ -790,13 +860,16 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
790
860
|
/**
|
|
791
861
|
* One chain transaction (`ixo.chain.tx.v1`) of 1–8 messages: the host
|
|
792
862
|
* adds the chain id and network (the account's), the signer (the
|
|
793
|
-
* owner's address) and the owner's identity
|
|
794
|
-
*
|
|
795
|
-
*
|
|
796
|
-
*
|
|
797
|
-
*
|
|
798
|
-
*
|
|
799
|
-
* digits than its decimals, zero or more than the listed balance.
|
|
863
|
+
* owner's address) and the owner's identity (`ChainTxOwnerField`:
|
|
864
|
+
* `did:ixo:<signer>`, an evaluation's `agentAddress` = the signer) and
|
|
865
|
+
* prepares it like any operation (no fee: the Hub simulates gas and
|
|
866
|
+
* sets it). A bank step's display `amount` is converted to base units
|
|
867
|
+
* from the owner's token list (one options read per call, only when
|
|
868
|
+
* there is a bank or stake step), refused for a token not listed, more
|
|
869
|
+
* digits than its decimals, zero or more than the listed balance. A
|
|
870
|
+
* stake step's IXO `amount` is converted with 6 decimals; what a stake
|
|
871
|
+
* takes from the wallet counts against the listed IXO balance with the
|
|
872
|
+
* IXO bank steps, when the list has IXO.
|
|
800
873
|
*/
|
|
801
874
|
chainTransaction(input: {
|
|
802
875
|
ownerDid: string;
|
|
@@ -821,11 +894,20 @@ export interface RuntimeContext<TConfig = MergedConfig> {
|
|
|
821
894
|
requestKey: string;
|
|
822
895
|
operation: ActionOperationV1;
|
|
823
896
|
}): Promise<ActionReferenceV1>;
|
|
824
|
-
/**
|
|
897
|
+
/**
|
|
898
|
+
* A fresh, authenticated read of one of this owner's actions: Auth
|
|
899
|
+
* Hub's review and operation status, the latest outcome (null: none
|
|
900
|
+
* yet) and, for a transfer, its owner-facing line. An action this
|
|
901
|
+
* owner object never prepared is `held: false` and Auth Hub is not
|
|
902
|
+
* asked. `timeoutMs` bounds the Hub read (default 10 s). Rejects with
|
|
903
|
+
* `HubActionRefused` (with `httpStatus`) when Auth Hub refuses the read,
|
|
904
|
+
* for example when it must be updated first.
|
|
905
|
+
*/
|
|
825
906
|
status(
|
|
826
907
|
ownerDid: string,
|
|
827
908
|
actionId: string,
|
|
828
|
-
|
|
909
|
+
opts?: { timeoutMs?: number },
|
|
910
|
+
): Promise<HubActionStatusRead>;
|
|
829
911
|
};
|
|
830
912
|
|
|
831
913
|
decisions: {
|
|
@@ -20,6 +20,9 @@ import { z } from 'zod';
|
|
|
20
20
|
import {
|
|
21
21
|
ATTACHMENT_VIEW_SOURCE,
|
|
22
22
|
buildUserMessageContent,
|
|
23
|
+
NOTE_FILENAME_MAX,
|
|
24
|
+
NOTE_MIMETYPE_MAX,
|
|
25
|
+
sanitizeNoteField,
|
|
23
26
|
VIEW_ATTACHMENT_TOOL_NAME,
|
|
24
27
|
} from '../../attachments';
|
|
25
28
|
import { tool } from '../../plugin-api/tool-helper';
|
|
@@ -30,7 +33,7 @@ export const viewAttachmentSchema = z.object({
|
|
|
30
33
|
.string()
|
|
31
34
|
.min(1)
|
|
32
35
|
.describe(
|
|
33
|
-
'The attachment reference exactly as listed in the "[attachment offloaded]" note of the message it belongs to (a Matrix event id such as "$abc…" or an mxc:// URI).',
|
|
36
|
+
'The attachment reference exactly as listed in the "[attachment offloaded]" note of the message it belongs to (a Matrix event id such as "$abc…", a channel file reference such as "channel:0123456789abcdef", or an mxc:// URI).',
|
|
34
37
|
),
|
|
35
38
|
});
|
|
36
39
|
|
|
@@ -52,12 +55,13 @@ export function createViewAttachmentTool(): PluginTool {
|
|
|
52
55
|
}
|
|
53
56
|
const { meta, view } = await ctx.attachments.view(ref);
|
|
54
57
|
if (view.kind === 'text') return view.text;
|
|
58
|
+
const name = sanitizeNoteField(meta.filename, NOTE_FILENAME_MAX);
|
|
55
59
|
if (!ctx.toolCallId) {
|
|
56
60
|
throw new Error(
|
|
57
|
-
`"${
|
|
61
|
+
`"${name}" was fetched but cannot be re-attached outside a tool call`,
|
|
58
62
|
);
|
|
59
63
|
}
|
|
60
|
-
const label = `Re-attached "${
|
|
64
|
+
const label = `Re-attached "${name}" (${sanitizeNoteField(meta.mimetype, NOTE_MIMETYPE_MAX)}) from earlier in this conversation.`;
|
|
61
65
|
const timestamp = new Date().toISOString();
|
|
62
66
|
const msgFromMatrixRoom = ctx.session.client === 'matrix';
|
|
63
67
|
return new Command({
|