feat(client): price a file attachment by the handle the model receives
A file block never reaches a model as bytes: dsh projects every one to `fileHandleText` at request assembly, and the token meter prices that handle in place of the block's structural JSON price. An attachment therefore costs a fixed ~60 tokens whatever its size, so the card now shows that price beside the size — computed from the three facts a log carries (name, byte size, digest prefix) and priced with the meter's own text arm, now shared with the fold's message price instead of restated there. The handle also names the stored copy's read path, which only the live environment resolves and no log holds, so the row prices the pathless arm and reads as a lower bound (`≥`) rather than an `≈`. The fold keeps the meter's fixed structural price for the same block, exactly as the harness does: one figure answers the request, the other the surface.
This commit is contained in:
1 parent
da43fe48c7
commit
dd05bbda4e
9 files changed
+129
-14
No files matched your search
@@ -56,9 +56,21 @@ describe('the attachment block', () => {
|
||||
assert.ok(text(imageCard).includes('3462×1211'), 'raw dimensions')
|
||||
assert.ok(text(imageCard).includes('1568×1350 · 146.2 kB'), 'sent dimensions and size')
|
||||
assert.ok(text(imageCard).includes('Token') && text(imageCard).includes('≈325'))
|
||||
// A file card keeps only its size: the extension badge already names the type.
|
||||
// A file card keeps its size and the floor its handle costs: the extension badge already names the type.
|
||||
assert.ok(!text(cards[0]).includes('Type'))
|
||||
assert.ok(text(cards[0]).includes('Size') && text(cards[0]).includes('2.6 kB'))
|
||||
assert.ok(text(cards[0]).includes('Token') && text(cards[0]).includes('≥58'), 'the handle floor')
|
||||
assert.ok(
|
||||
text(cards[1]).includes('≥56') && text(cards[2]).includes('≥56'),
|
||||
'a 778 kB docx costs no more than a 47 kB markdown: only the handle travels',
|
||||
)
|
||||
// The two token rows read differently on purpose: a vision price, and a lower bound.
|
||||
const fileTip = queryAll(cards[0], '.lc-att-row').pop()?.getAttribute('title') ?? ''
|
||||
assert.ok(fileTip.includes('lower bound') && fileTip.includes('never its contents'), fileTip)
|
||||
assert.ok(
|
||||
(queryAll(cards[3], '.lc-att-row').pop()?.getAttribute('title') ?? '').includes('image-size conversion'),
|
||||
'the image row keeps the vision calculator as its explanation',
|
||||
)
|
||||
assert.ok(text(cards[3]).includes('Type'), 'an image has no badge, so its type keeps the row')
|
||||
// Every card invites the same one click.
|
||||
assert.ok(queryAll(m.container, '.lc-att-hint').every(hint => text(hint).includes('Click to preview')))
|
||||
@@ -78,12 +90,14 @@ describe('the attachment block', () => {
|
||||
await bare.unmount()
|
||||
})
|
||||
|
||||
test('an unnamed file names its kind on the badge, and shows no size row', async () => {
|
||||
test('an unnamed file names its kind on the badge, and shows no size or token row', async () => {
|
||||
const m = await mountSection({ attachments: [{ kind: 'file', attachmentId: 'sha256:u' }] })
|
||||
const card = query(m.container, '.lc-att-item')
|
||||
assert.ok(text(query(card, '.lc-att-name')).includes('File'))
|
||||
assert.equal(text(query(card, '.lc-att-ext')), 'File', 'the kind stands in for a missing extension')
|
||||
assert.ok(!text(card).includes('Size'))
|
||||
// The handle names the file and its size, so an unproven reference prices nothing.
|
||||
assert.ok(!text(card).includes('Token'))
|
||||
await m.unmount()
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// The per-file attachment price (src/shared/fileTokens.ts): what a durable file costs in a request,
|
||||
// which is the harness's model-facing handle and never the file's bytes.
|
||||
|
||||
import assert from 'node:assert/strict'
|
||||
import { describe, test } from 'vitest'
|
||||
import { estimateFileTokens } from '../../src/shared/fileTokens'
|
||||
|
||||
const DIGEST = 'sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'
|
||||
|
||||
function file(over: { name?: string; bytes?: number; attachmentId?: string } = {}) {
|
||||
return { attachmentId: DIGEST, name: 'notes.md', bytes: 120, ...over }
|
||||
}
|
||||
|
||||
describe('estimateFileTokens', () => {
|
||||
test('the price is the harness handle priced as one text block', () => {
|
||||
// The handle the harness emits when the environment cannot read the stored copy, verbatim.
|
||||
const handle = '[File "notes.md" (120 bytes, sha256:01234567) was uploaded, but the current execution'
|
||||
+ ' environment cannot access a readable path. Report that limitation if its contents are needed;'
|
||||
+ ' do not claim to have read it.]'
|
||||
assert.equal(estimateFileTokens(file()), Math.ceil(handle.length / 4) + 4)
|
||||
assert.equal(estimateFileTokens(file()), 57)
|
||||
})
|
||||
|
||||
test('a 778 kB file costs one token more than a 120 B one: the bytes are never sent', () => {
|
||||
assert.equal(estimateFileTokens(file({ bytes: 778_285 })), 58)
|
||||
})
|
||||
|
||||
test('only the digest prefix reaches the handle', () => {
|
||||
assert.equal(estimateFileTokens(file({ attachmentId: `sha256:01234567${'0'.repeat(56)}` })), 57)
|
||||
assert.equal(estimateFileTokens(file({ attachmentId: `sha256:${'f'.repeat(64)}` })), 57)
|
||||
})
|
||||
|
||||
test('the price is a floor: the arm that names the stored copy costs more', () => {
|
||||
// The other harness arm appends the copy's read path, which only the live environment resolves.
|
||||
const pathArm = ' verbatim read-only copy saved at "/home/u/.dsh/attachments/v1/files/ab/0123456789abcdef'
|
||||
+ '/notes.md". Read that path with your file tools when its contents are needed; copy it to a'
|
||||
+ ' writable location before modifying it. When delegating file work, include this saved path in the'
|
||||
+ ' delegation prompt; only subagents sharing this execution environment can read it.'
|
||||
assert.ok(Math.ceil((400 + pathArm.length) / 4) + 4 > (estimateFileTokens(file()) as number))
|
||||
})
|
||||
|
||||
test('a name or a byte size the log does not prove prices nothing', () => {
|
||||
assert.equal(estimateFileTokens(file({ name: undefined })), null)
|
||||
assert.equal(estimateFileTokens(file({ bytes: undefined })), null)
|
||||
assert.equal(estimateFileTokens(file({ name: undefined, bytes: undefined })), null)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user