@animalabs/agent-framework 0.22.3 → 0.23.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/README.md +105 -3
- package/dist/src/agent.d.ts +36 -10
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +76 -32
- package/dist/src/agent.js.map +1 -1
- package/dist/src/code-execution/index.d.ts +1 -1
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/py-runner.d.ts +34 -2
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +72 -16
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts +3 -2
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +47 -7
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts +12 -7
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +59 -11
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/config-checks.d.ts +2 -2
- package/dist/src/config-checks.d.ts.map +1 -1
- package/dist/src/config-checks.js +6 -2
- package/dist/src/config-checks.js.map +1 -1
- package/dist/src/framework.d.ts +744 -120
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +3546 -906
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +13 -6
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -0
- package/dist/src/held-writes.d.ts.map +1 -0
- package/dist/src/held-writes.js +56 -0
- package/dist/src/held-writes.js.map +1 -0
- package/dist/src/index.d.ts +7 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts +4 -0
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
- package/dist/src/mcpl/capability-grant.js +1 -1
- package/dist/src/mcpl/capability-grant.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +95 -18
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +578 -150
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +2 -2
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +6 -7
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +5 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +4 -2
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +6 -7
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +7 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +9 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +227 -0
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -0
- package/dist/src/mcpl/modern-connection.js +1088 -0
- package/dist/src/mcpl/modern-connection.js.map +1 -0
- package/dist/src/mcpl/prefix-rule.d.ts +18 -0
- package/dist/src/mcpl/prefix-rule.d.ts.map +1 -0
- package/dist/src/mcpl/prefix-rule.js +25 -0
- package/dist/src/mcpl/prefix-rule.js.map +1 -0
- package/dist/src/mcpl/protocol-family.d.ts +179 -0
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -0
- package/dist/src/mcpl/protocol-family.js +697 -0
- package/dist/src/mcpl/protocol-family.js.map +1 -0
- package/dist/src/mcpl/push-coalescer.d.ts +38 -19
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +52 -23
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +66 -15
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +243 -76
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +63 -18
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +117 -32
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +326 -30
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +995 -212
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts +25 -5
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +51 -12
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.d.ts +54 -0
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -0
- package/dist/src/mcpl/tool-result-normalize.js +232 -0
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +56 -13
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +206 -70
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +66 -20
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/mcpl/visible-content.d.ts +2 -1
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +2 -1
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +16 -6
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +65 -6
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +3 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/discord-js-client.d.ts +42 -2
- package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
- package/dist/src/modules/discord/discord-js-client.js +268 -65
- package/dist/src/modules/discord/discord-js-client.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +27 -5
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +366 -76
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/discord/refusal.d.ts +14 -0
- package/dist/src/modules/discord/refusal.d.ts.map +1 -0
- package/dist/src/modules/discord/refusal.js +14 -0
- package/dist/src/modules/discord/refusal.js.map +1 -0
- package/dist/src/modules/discord/types.d.ts +17 -7
- package/dist/src/modules/discord/types.d.ts.map +1 -1
- package/dist/src/modules/health/index.d.ts.map +1 -1
- package/dist/src/modules/health/index.js +6 -2
- package/dist/src/modules/health/index.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +25 -2
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +45 -5
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +2 -1
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +19 -9
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +214 -42
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +667 -113
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +240 -8
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +554 -24
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +10 -1
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +42 -0
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js +130 -25
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/silent-heartbeat.d.ts +112 -39
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +100 -29
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/tool-args.d.ts +40 -0
- package/dist/src/tool-args.d.ts.map +1 -0
- package/dist/src/tool-args.js +207 -0
- package/dist/src/tool-args.js.map +1 -0
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +9 -2
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/types/agent.d.ts +27 -17
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +8 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +17 -2
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +54 -10
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +2 -2
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/agent.ts +99 -36
- package/src/code-execution/index.ts +1 -0
- package/src/code-execution/py-runner.ts +104 -17
- package/src/code-execution/runtime-py.ts +47 -7
- package/src/code-execution/tool-definition.ts +65 -11
- package/src/config-checks.ts +4 -2
- package/src/framework.ts +3633 -956
- package/src/gate/event-gate.ts +14 -6
- package/src/held-writes.ts +59 -0
- package/src/index.ts +19 -4
- package/src/mcpl/capability-grant.ts +1 -1
- package/src/mcpl/channel-registry.ts +613 -160
- package/src/mcpl/convert-block.ts +15 -7
- package/src/mcpl/index.ts +14 -1
- package/src/mcpl/inference-router.ts +8 -7
- package/src/mcpl/log-value.ts +10 -0
- package/src/mcpl/modern-connection.ts +1182 -0
- package/src/mcpl/prefix-rule.ts +32 -0
- package/src/mcpl/protocol-family.ts +691 -0
- package/src/mcpl/push-coalescer.ts +67 -29
- package/src/mcpl/reference-fetcher.ts +288 -82
- package/src/mcpl/references.ts +123 -33
- package/src/mcpl/server-connection.ts +1050 -221
- package/src/mcpl/server-registry.ts +50 -12
- package/src/mcpl/tool-result-normalize.ts +294 -0
- package/src/mcpl/transport.ts +204 -62
- package/src/mcpl/types.ts +67 -20
- package/src/mcpl/visible-content.ts +2 -1
- package/src/module-registry.ts +68 -13
- package/src/modules/api/index.ts +3 -2
- package/src/modules/discord/discord-js-client.ts +288 -72
- package/src/modules/discord/index.ts +380 -77
- package/src/modules/discord/refusal.ts +13 -0
- package/src/modules/discord/types.ts +17 -9
- package/src/modules/health/index.ts +6 -2
- package/src/modules/index.ts +1 -1
- package/src/modules/workspace/disk-agreement.ts +46 -5
- package/src/modules/workspace/effects.ts +18 -7
- package/src/modules/workspace/index.ts +722 -124
- package/src/modules/workspace/observe.ts +591 -22
- package/src/modules/workspace/types.ts +10 -1
- package/src/modules/workspace/watcher.ts +126 -25
- package/src/silent-heartbeat.ts +184 -59
- package/src/tool-args.ts +213 -0
- package/src/tool-presentation.ts +9 -2
- package/src/types/agent.ts +27 -17
- package/src/types/events.ts +8 -0
- package/src/types/framework.ts +17 -2
- package/src/types/module.ts +55 -10
- package/src/types/trace.ts +2 -2
package/src/mcpl/references.ts
CHANGED
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
* code-execution materialization hook possible.
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
|
+
import { NON_STRING_TEXT_PLACEHOLDER } from './visible-content.js';
|
|
30
|
+
|
|
29
31
|
export const REFERENCE_LIMITS = { uri: 4096, mimeType: 255, name: 255, expiresAt: 64 } as const;
|
|
30
32
|
export const DIGEST_PATTERN = /^sha256:[A-Za-z0-9_-]{43}$/;
|
|
31
33
|
const MAX_SAFE = 9007199254740991; // 2^53 - 1
|
|
@@ -53,7 +55,8 @@ export type BlockClassification =
|
|
|
53
55
|
| { kind: 'text' }
|
|
54
56
|
| { kind: 'inline'; contradiction: boolean }
|
|
55
57
|
| { kind: 'reference'; testimony: ReferenceTestimony }
|
|
56
|
-
|
|
58
|
+
/** `shown` is what the model-visible lanes put in the block's place. */
|
|
59
|
+
| { kind: 'invalid'; shown: string };
|
|
57
60
|
|
|
58
61
|
function isRecord(x: unknown): x is Record<string, unknown> {
|
|
59
62
|
return typeof x === 'object' && x !== null && !Array.isArray(x);
|
|
@@ -80,13 +83,13 @@ function takeString(
|
|
|
80
83
|
|
|
81
84
|
export function classifyBlock(block: unknown): BlockClassification {
|
|
82
85
|
if (!isRecord(block) || typeof block.type !== 'string') {
|
|
83
|
-
return { kind: 'invalid',
|
|
86
|
+
return { kind: 'invalid', shown: unknownBlockText(block) };
|
|
84
87
|
}
|
|
85
88
|
switch (block.type) {
|
|
86
89
|
case 'text':
|
|
87
90
|
return typeof block.text === 'string'
|
|
88
91
|
? { kind: 'text' }
|
|
89
|
-
: { kind: 'invalid',
|
|
92
|
+
: { kind: 'invalid', shown: NON_STRING_TEXT_PLACEHOLDER };
|
|
90
93
|
case 'image':
|
|
91
94
|
case 'audio': {
|
|
92
95
|
const hasData = typeof block.data === 'string';
|
|
@@ -94,32 +97,30 @@ export function classifyBlock(block: unknown): BlockClassification {
|
|
|
94
97
|
if (hasData) {
|
|
95
98
|
// Inline form claiming bulk disposition (or smuggling a uri beside
|
|
96
99
|
// the data) is the vector-2 contradiction: fail closed, withhold.
|
|
100
|
+
// A uri of '' counts here too, though it's no link: until the
|
|
101
|
+
// tool-result lane gives every inline shape a marker of its own,
|
|
102
|
+
// showing that data would put some of it into history as raw JSON.
|
|
103
|
+
// Once that lane does, an empty link beside data reads as no link.
|
|
97
104
|
return { kind: 'inline', contradiction: block.disposition !== undefined || hasUri };
|
|
98
105
|
}
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
// With no data, an empty uri is no link, as the push lane's converter
|
|
107
|
+
// reads it.
|
|
108
|
+
if (hasUri && block.uri !== '') return parseReferenceFields(block);
|
|
109
|
+
return { kind: 'invalid', shown: block.type === 'image' ? IMAGE_NO_DATA_TEXT : AUDIO_NO_DATA_TEXT };
|
|
101
110
|
}
|
|
102
111
|
case 'resource':
|
|
103
112
|
return parseReferenceFields(block);
|
|
104
113
|
default:
|
|
105
|
-
return { kind: 'invalid',
|
|
114
|
+
return { kind: 'invalid', shown: unknownBlockText(block) };
|
|
106
115
|
}
|
|
107
116
|
}
|
|
108
117
|
|
|
109
|
-
/** What a media block with neither string data nor a string uri has instead:
|
|
110
|
-
* nothing, or a field that isn't a string. */
|
|
111
|
-
function mediaWithoutStringReason(block: Record<string, unknown>): string {
|
|
112
|
-
const notString = (['data', 'uri'] as const).filter((f) => block[f] !== undefined && block[f] !== null);
|
|
113
|
-
if (notString.length === 0) return 'with neither data nor uri';
|
|
114
|
-
return notString.length === 2 ? "whose data and uri aren't strings" : `whose ${notString[0]} isn't a string`;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
118
|
function parseReferenceFields(block: Record<string, unknown>): BlockClassification {
|
|
118
119
|
if (typeof block.uri !== 'string' || block.uri.length === 0) {
|
|
119
|
-
return { kind: 'invalid',
|
|
120
|
+
return { kind: 'invalid', shown: REFERENCE_NO_LINK_TEXT };
|
|
120
121
|
}
|
|
121
122
|
if (block.uri.length > REFERENCE_LIMITS.uri) {
|
|
122
|
-
return { kind: 'invalid',
|
|
123
|
+
return { kind: 'invalid', shown: REFERENCE_LINK_TOO_LONG_TEXT };
|
|
123
124
|
}
|
|
124
125
|
const out = { rejected: [] as string[], truncated: [] as string[] };
|
|
125
126
|
const t: ReferenceTestimony = { uri: block.uri, rejectedFields: out.rejected, truncatedFields: out.truncated };
|
|
@@ -152,7 +153,38 @@ export function isInlineContradiction(block: unknown): boolean {
|
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
export const INLINE_WITHHELD_TEXT =
|
|
155
|
-
'[
|
|
156
|
+
'[Content not shown: its inline data arrived marked as a reference too, so this host withheld it.]';
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
* What the model-visible lanes (push, channel, context injection and tool
|
|
160
|
+
* results) put in place of a block they can't show as itself. Each says what
|
|
161
|
+
* kind of thing was there and why it can't be seen, in the host's words, so
|
|
162
|
+
* the agent doesn't read the content as complete; there's nothing for the
|
|
163
|
+
* agent to do about any of them. The text marker is NON_STRING_TEXT_PLACEHOLDER
|
|
164
|
+
* (visible-content.ts).
|
|
165
|
+
*/
|
|
166
|
+
export const IMAGE_NO_MEDIA_TYPE_TEXT = '[Image not shown: its data arrived without a media type.]';
|
|
167
|
+
export const IMAGE_NO_DATA_TEXT = '[Image not shown: it arrived with no usable data or link.]';
|
|
168
|
+
export const AUDIO_NO_MEDIA_TYPE_TEXT = '[Audio not shown: its data arrived without a media type.]';
|
|
169
|
+
/** On the push, channel and context-injection lanes, audio shows only as
|
|
170
|
+
* inline data, so a plain link isn't enough either. (A tool result's audio
|
|
171
|
+
* with a link is a reference, as any block with one is there.) */
|
|
172
|
+
export const AUDIO_NO_DATA_TEXT = '[Audio not shown: it arrived with no usable inline data.]';
|
|
173
|
+
export const REFERENCE_NO_LINK_TEXT = '[Reference not shown: it arrived without a link.]';
|
|
174
|
+
export const REFERENCE_LINK_TOO_LONG_TEXT = '[Reference not shown: its link is longer than this host accepts.]';
|
|
175
|
+
const UNREADABLE_BLOCK_TEXT = "[Content not shown: a part arrived in a form this host can't read.]";
|
|
176
|
+
|
|
177
|
+
/** A block of a type the host doesn't show, of no type at all, or no block.
|
|
178
|
+
* The type is the sender's word, so it's shown as a label is: bounded, with
|
|
179
|
+
* its controls removed. One that isn't a string is no type, and is never
|
|
180
|
+
* converted to one. */
|
|
181
|
+
export function unknownBlockText(block: unknown): string {
|
|
182
|
+
if (!isRecord(block)) return UNREADABLE_BLOCK_TEXT;
|
|
183
|
+
const label = typeof block.type === 'string' ? sanitizeLabel(block.type, STUB_FIELD_CHARS) : '';
|
|
184
|
+
return label
|
|
185
|
+
? `[Content not shown: this host can't display "${label}" content.]`
|
|
186
|
+
: '[Content not shown: a part arrived with no type.]';
|
|
187
|
+
}
|
|
156
188
|
|
|
157
189
|
/**
|
|
158
190
|
* Why a reference counts as expired, or null when it doesn't: its expiresAt
|
|
@@ -177,17 +209,28 @@ export function isReferenceExpired(t: Pick<ReferenceTestimony, 'expiresAt' | 're
|
|
|
177
209
|
return referenceExpiry(t, nowMs) !== null;
|
|
178
210
|
}
|
|
179
211
|
|
|
180
|
-
/** Each expiry case as the stub
|
|
212
|
+
/** Each expiry case in the agent's words, as the stub, the fetcher's refusal
|
|
213
|
+
* and save_recent_image's refusal all say it. */
|
|
181
214
|
export const EXPIRY_REASON = {
|
|
182
|
-
passed: 'expired
|
|
183
|
-
unparseable:
|
|
184
|
-
rejected:
|
|
215
|
+
passed: 'expired',
|
|
216
|
+
unparseable: "treated as expired, since its expiry time can't be read",
|
|
217
|
+
rejected: "treated as expired, since its expiry time isn't in a form this host accepts",
|
|
185
218
|
} as const;
|
|
186
219
|
|
|
187
|
-
/** A reference registered with no server,
|
|
188
|
-
* and save_recent_image's all say it: the fetcher dials
|
|
189
|
-
* server that delivered the reference. */
|
|
190
|
-
export const UNBOUND_REASON =
|
|
220
|
+
/** A reference registered with no server, in the agent's words, as the stub,
|
|
221
|
+
* the fetcher's refusal and save_recent_image's all say it: the fetcher dials
|
|
222
|
+
* only through a server that delivered the reference. */
|
|
223
|
+
export const UNBOUND_REASON = "not tied to any server, so there's nowhere to fetch it from";
|
|
224
|
+
|
|
225
|
+
/** The fetcher's refusal for a server it has no address to dial, one the
|
|
226
|
+
* host doesn't connect to over a network, such as a stdio server, as a
|
|
227
|
+
* clause that completes "couldn't fetch <ref>: " and says so of the server;
|
|
228
|
+
* the fetcher dials only through a server's address. save_recent_image gives
|
|
229
|
+
* it too. A stub can't know it, since only the framework holds its servers'
|
|
230
|
+
* configs. */
|
|
231
|
+
export function noAddressReason(serverId: string): string {
|
|
232
|
+
return `this host doesn't connect to the "${serverId}" server over a network, so there's nowhere to fetch it from`;
|
|
233
|
+
}
|
|
191
234
|
|
|
192
235
|
/** Strip control characters (C0, DEL, C1) and every bidi control (marks,
|
|
193
236
|
* embeddings, overrides, isolates, and the Arabic letter mark), trim the
|
|
@@ -371,13 +414,15 @@ export function buildReferenceStub(t: ReferenceTestimony, provenance?: string, s
|
|
|
371
414
|
}
|
|
372
415
|
|
|
373
416
|
/**
|
|
374
|
-
* Why the fetcher would refuse a reference, as far as its record shows
|
|
375
|
-
* server registered for it, which the fetcher checks first,
|
|
376
|
-
* Null for a saved copy, which the fetcher serves before any
|
|
377
|
-
* the record shows neither. The fetcher's other refusals rest
|
|
378
|
-
* doesn't hold: whether any of its servers is
|
|
379
|
-
* the uri's origin,
|
|
380
|
-
*
|
|
417
|
+
* Why the fetcher would refuse a reference, as far as its record alone shows,
|
|
418
|
+
* for its stub: no server registered for it, which the fetcher checks first,
|
|
419
|
+
* or its expiry. Null for a saved copy, which the fetcher serves before any
|
|
420
|
+
* check, and when the record shows neither. The fetcher's other refusals rest
|
|
421
|
+
* on what a record doesn't hold: whether any of its servers is known to the
|
|
422
|
+
* host, has an address and is on the uri's origin, the dialed server's fetch
|
|
423
|
+
* budget spent, or a claimed size over the ceiling a fetch is given. The
|
|
424
|
+
* fetcher gives those in its own words, and save_recent_image, in the
|
|
425
|
+
* framework where it can ask the fetcher, says them too.
|
|
381
426
|
*/
|
|
382
427
|
export function unfetchableReason(record: ReferenceRecord, nowMs = Date.now()): string | null {
|
|
383
428
|
if (record.fetchedPath) return null;
|
|
@@ -398,6 +443,51 @@ export function referenceStubOrNull(block: unknown, provenance?: string, serverI
|
|
|
398
443
|
case 'inline':
|
|
399
444
|
return c.contradiction ? INLINE_WITHHELD_TEXT : null;
|
|
400
445
|
case 'reference': return buildReferenceStub(c.testimony, provenance, serverId);
|
|
401
|
-
case 'invalid': return
|
|
446
|
+
case 'invalid': return c.shown;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* RFC-005 treatment for one MCPL wire block, for a script's structured
|
|
452
|
+
* result, which carries blocks rather than text. It makes the decision
|
|
453
|
+
* referenceStubOrNull makes for the model's lanes, since what a script prints
|
|
454
|
+
* comes back to the model. A reference becomes the stub's facts as data,
|
|
455
|
+
* without its URI: the host's reference id, what the server said about it in
|
|
456
|
+
* this block (its labels stripped and bounded as in the stub), and `savedTo`,
|
|
457
|
+
* the workspace path its payload was fetched to, or null when it wasn't
|
|
458
|
+
* (`fetch_reference` takes the id as `ref_id`). An unsaved reference that
|
|
459
|
+
* counts as expired also carries `expired`, the reason the stub gives in
|
|
460
|
+
* place of advising fetch_reference. The reference is registered bound to
|
|
461
|
+
* `serverId`, the server whose tool returned it, as the model's lanes bind
|
|
462
|
+
* a tool result's references, so the fetch its id offers can be made. A
|
|
463
|
+
* block the classifier
|
|
464
|
+
* rejects becomes the notice the model's lanes show, and inline data that
|
|
465
|
+
* also claims a bulk disposition the withheld notice, each as a text block.
|
|
466
|
+
* A text block, or inline data that claims nothing, is returned as sent.
|
|
467
|
+
*/
|
|
468
|
+
export function referenceBlockForScript(block: unknown, serverId: string): unknown {
|
|
469
|
+
const c = classifyBlock(block);
|
|
470
|
+
switch (c.kind) {
|
|
471
|
+
case 'text': return block;
|
|
472
|
+
case 'inline':
|
|
473
|
+
return c.contradiction ? { type: 'text', text: INLINE_WITHHELD_TEXT } : block;
|
|
474
|
+
case 'invalid': return { type: 'text', text: c.shown };
|
|
475
|
+
case 'reference': {
|
|
476
|
+
const t = c.testimony;
|
|
477
|
+
const record = referenceRegistry.register(t, serverId);
|
|
478
|
+
// As the stub judges it: a saved copy is still served.
|
|
479
|
+
const expiry = record.fetchedPath ? null : referenceExpiry(record.testimony);
|
|
480
|
+
return {
|
|
481
|
+
type: (block as { type: string }).type,
|
|
482
|
+
refId: record.refId,
|
|
483
|
+
...(t.name !== undefined ? { name: sanitizeLabel(t.name, STUB_FIELD_CHARS) } : {}),
|
|
484
|
+
...(t.mimeType !== undefined ? { mimeType: sanitizeLabel(t.mimeType, STUB_FIELD_CHARS) } : {}),
|
|
485
|
+
...(t.sizeBytes !== undefined ? { sizeBytes: t.sizeBytes } : {}),
|
|
486
|
+
...(t.digest !== undefined ? { digest: t.digest } : {}),
|
|
487
|
+
...(t.expiresAt !== undefined ? { expiresAt: sanitizeLabel(t.expiresAt, STUB_FIELD_CHARS) } : {}),
|
|
488
|
+
savedTo: record.fetchedPath ?? null,
|
|
489
|
+
...(expiry ? { expired: EXPIRY_REASON[expiry] } : {}),
|
|
490
|
+
};
|
|
491
|
+
}
|
|
402
492
|
}
|
|
403
493
|
}
|