@inetafrica/open-claudia 3.4.13 → 3.4.14
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.4.14
|
|
4
|
+
|
|
5
|
+
- Subscribe to managed call audio only when gateway-authenticated publisher metadata identifies a User. Exclude bots, the current bot's other feeds, and missing or malformed classifications before creating subscriber connections or speech streams.
|
|
6
|
+
- Preserve metadata through the initial room response and live publisher events. Managed calls use that authenticated classification; legacy calls retain their existing display-prefix exclusion because client-supplied metadata is untrusted.
|
|
7
|
+
- Exercise the actual session subscription and offer/answer path for allowed users and rejected bot, self and unknown feeds.
|
|
8
|
+
|
|
3
9
|
## 3.4.13
|
|
4
10
|
|
|
5
11
|
- **Codex is now measured the way Claude is.** After each Codex turn the bot reads Codex's own per-request token log (`$CODEX_HOME/sessions/…/rollout-*-<thread>.jsonl`) and uses the last request's size as the live context, instead of the turn's input summed over every tool call. That sum (33M on one turn) tripped auto-compact after almost every substantial Codex turn — 8 needless compactions on 2026-09-05, each a summary run plus a cold restart — while Codex's real window occupancy never exceeded 245k of its 258k window. Codex sessions now compact at 80% of the window Codex reports.
|
|
@@ -256,8 +256,8 @@ class KazeeCallSession {
|
|
|
256
256
|
}
|
|
257
257
|
for (const publisher of data.publishers || []) {
|
|
258
258
|
const feedId = Number(publisher.id);
|
|
259
|
-
if (Number.isSafeInteger(feedId) && feedId > 0 && feedId !== this.publisherId && !this.subscribers.has(feedId)
|
|
260
|
-
await this._subscribe(feedId, publisher.display);
|
|
259
|
+
if (Number.isSafeInteger(feedId) && feedId > 0 && feedId !== this.publisherId && !this.subscribers.has(feedId)) {
|
|
260
|
+
await this._subscribe(feedId, publisher.display, publisher.metadata);
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
if (data.videoroom === "joined") {
|
|
@@ -357,8 +357,21 @@ class KazeeCallSession {
|
|
|
357
357
|
this.speak(this.greeting).catch((error) => console.error("Kazee call greeting:", error.message));
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
async _subscribe(feedId, display) {
|
|
361
|
-
if (this.subscribers.has(feedId)) return;
|
|
360
|
+
async _subscribe(feedId, display, metadata) {
|
|
361
|
+
if (this.closed || feedId === this.publisherId || this.subscribers.has(feedId)) return;
|
|
362
|
+
if (this.managedRoom) {
|
|
363
|
+
// Only the enforced gateway owns this metadata. Display remains an email
|
|
364
|
+
// for presentation, and cannot tell us whether a publisher is another bot.
|
|
365
|
+
// Missing or malformed classification must not start STT on an unknown feed.
|
|
366
|
+
const principal = metadata?.kazee;
|
|
367
|
+
if (!principal || Array.isArray(principal) || principal.version !== 1 ||
|
|
368
|
+
typeof principal.userId !== "string" || !/^[a-f\d]{24}$/i.test(principal.userId) ||
|
|
369
|
+
!["User", "Bot"].includes(principal.principalKind) || principal.principalKind === "Bot" ||
|
|
370
|
+
principal.userId.toLowerCase() === this.botUserId.toLowerCase()) return;
|
|
371
|
+
} else if (String(display || "").startsWith("open-claudia:")) {
|
|
372
|
+
// Legacy/direct rooms allow client metadata, so it is not a trusted source.
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
362
375
|
// Reserve the slot before the first await: the join response and the async
|
|
363
376
|
// publishers event both list the same feed, and while attach() is in
|
|
364
377
|
// flight the second frame passes the caller's has() check and subscribes
|
package/package.json
CHANGED
|
@@ -462,10 +462,11 @@ async function testManagedRoomCredentials() {
|
|
|
462
462
|
assert.strictEqual(session.janus.options.token, "root-token");
|
|
463
463
|
assert.strictEqual(session.janus.calls[0].token, "publisher-token");
|
|
464
464
|
await session._consumePublisherFrame({ plugindata: { data: { publishers: [{ id: 41, display: 'canonical-bot@calling.invalid' }, { id: 42, display: 'open-claudia:legacy-bot' }] } } });
|
|
465
|
-
assert.strictEqual(session.subscribers.size, 0, 'own joined publisher ID
|
|
465
|
+
assert.strictEqual(session.subscribers.size, 0, 'own joined publisher ID and unclassified managed feeds are excluded independently of display');
|
|
466
466
|
|
|
467
467
|
session.roomTokenExpiresAt = Date.now() - 1;
|
|
468
|
-
|
|
468
|
+
const userMetadata = { kazee: { version: 1, userId: 'a'.repeat(24), principalKind: 'User' } };
|
|
469
|
+
await Promise.all([session._subscribe(17, "owner", userMetadata), session._subscribe(18, "other", userMetadata)]);
|
|
469
470
|
const subJoin = session.janus.calls.find(body => body.ptype === "subscriber");
|
|
470
471
|
assert.strictEqual(subJoin.token, "subscriber-token");
|
|
471
472
|
assert.strictEqual(subJoin.private_id, 999);
|
|
@@ -484,6 +485,66 @@ async function testManagedRoomCredentials() {
|
|
|
484
485
|
assert.ok(!session.janus.calls.some(body => ["create", "destroy"].includes(body.request)), "server allocated room ownership never transfers to the bot");
|
|
485
486
|
}
|
|
486
487
|
|
|
488
|
+
async function testTrustedPublisherMetadata() {
|
|
489
|
+
const botId = 'b'.repeat(24), userId = 'a'.repeat(24);
|
|
490
|
+
const metadata = (principalKind, id = userId) => ({ kazee: { version: 1, userId: id, principalKind } });
|
|
491
|
+
const publisher = (id, meta, display = 'speaker@calling.invalid') => ({ id, display, metadata: meta });
|
|
492
|
+
let initial = [];
|
|
493
|
+
class MetadataJanus extends FakeJanus {
|
|
494
|
+
constructor() { super(); this.calls = []; this.listeners = new Map(); }
|
|
495
|
+
onHandle(handle, listener) { this.listeners.set(handle, listener); }
|
|
496
|
+
async message(handle, body) {
|
|
497
|
+
this.calls.push({ handle, ...body });
|
|
498
|
+
if (body.request === 'join' && body.ptype === 'publisher') return { plugindata: { data: { videoroom: 'joined', id: 41, private_id: 999, publishers: initial } } };
|
|
499
|
+
if (body.request === 'configure') return { jsep: { type: 'answer', sdp: 'fixture' } };
|
|
500
|
+
if (body.request === 'join' && body.ptype === 'subscriber') return { plugindata: { data: { videoroom: 'attached' } }, jsep: { type: 'offer', sdp: 'fixture' } };
|
|
501
|
+
return {};
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const make = managedRoom => new KazeeCallSession({ roomId: 7, chatId: 'chat', callerId: userId, botUserId: botId, managedRoom,
|
|
505
|
+
roomToken: 'fixture', roomTokenExpiresAt: Date.now() + 300000,
|
|
506
|
+
iceServers: [{ urls: 'turn:relay:3478', username: 'fixture', credential: 'fixture' }], iceCredentialsExpiresAt: Date.now() + 3600000,
|
|
507
|
+
JanusClientImpl: MetadataJanus, PeerConnectionImpl: FakePC, SpeechStreamImpl: FakeSpeechStream });
|
|
508
|
+
const invalid = [undefined, null, {}, { kazee: null }, { kazee: [] },
|
|
509
|
+
{ kazee: { version: 2, userId, principalKind: 'User' } }, { kazee: { version: '1', userId, principalKind: 'User' } },
|
|
510
|
+
metadata('Human'), metadata('bot'), metadata(undefined), metadata('User', 'invalid'), { kazee: { version: 1, principalKind: 'User' } },
|
|
511
|
+
{ kazee: { version: 1, userId: { $ne: null }, principalKind: 'User' } }];
|
|
512
|
+
initial = [publisher(41, metadata('User')), publisher(42, metadata('Bot', 'c'.repeat(24)), 'other-bot@calling.invalid'),
|
|
513
|
+
publisher(43, metadata('User')), publisher(44, metadata('User', botId.toUpperCase())),
|
|
514
|
+
...invalid.map((meta, i) => publisher(100 + i, meta))];
|
|
515
|
+
const managed = make(true);
|
|
516
|
+
try {
|
|
517
|
+
await managed.start();
|
|
518
|
+
assert.deepStrictEqual([...managed.subscribers.keys()], [43], 'initial join reaches real subscription only for a classified human, never self/bot/unknown');
|
|
519
|
+
assert.strictEqual(managed.subscribers.get(43).started, true, 'authorized human reaches the actual subscriber offer/answer path');
|
|
520
|
+
const emit = publishers => managed.janus.listeners.get(managed.publisherHandle)({ janus: 'event', plugindata: { data: { publishers } } });
|
|
521
|
+
await emit([publisher(50, metadata('Bot', 'd'.repeat(24)), 'another-bot@calling.invalid'),
|
|
522
|
+
publisher(51, metadata('User'), 'open-claudia:display-is-not-managed-authority'),
|
|
523
|
+
...invalid.map((meta, i) => publisher(200 + i, meta))]);
|
|
524
|
+
assert.deepStrictEqual([...managed.subscribers.keys()], [43, 51], 'live publisher metadata survives forwarding; managed classification never falls back to display prefix');
|
|
525
|
+
assert.strictEqual(managed.subscribers.get(51).display, 'open-claudia:display-is-not-managed-authority', 'presentation remains unchanged');
|
|
526
|
+
const handles = managed.janus.handles;
|
|
527
|
+
await managed._subscribe(60, 'unclassified@calling.invalid');
|
|
528
|
+
await managed._subscribe(61, 'bot@calling.invalid', metadata('Bot'));
|
|
529
|
+
await managed._subscribe(41, 'own@calling.invalid', metadata('User'));
|
|
530
|
+
assert.strictEqual(managed.janus.handles, handles, 'the subscription method itself fails closed before creating handles or speech streams');
|
|
531
|
+
assert.deepStrictEqual(managed.janus.calls.filter(body => body.ptype === 'subscriber').map(body => body.feed), [43, 51]);
|
|
532
|
+
} finally { await managed.close(); }
|
|
533
|
+
|
|
534
|
+
initial = [publisher(41, metadata('User')), publisher(42, metadata('User'), 'open-claudia:legacy-bot'),
|
|
535
|
+
publisher(43, metadata('Bot'), 'human@calling.invalid')];
|
|
536
|
+
const legacy = make(false);
|
|
537
|
+
try {
|
|
538
|
+
await legacy.start();
|
|
539
|
+
assert.deepStrictEqual([...legacy.subscribers.keys()], [43], 'legacy metadata cannot hide a human or impersonate one for a prefixed bot; own numeric feed remains excluded');
|
|
540
|
+
await legacy.janus.listeners.get(legacy.publisherHandle)({ janus: 'event', plugindata: { data: { publishers: [
|
|
541
|
+
publisher(50, metadata('Bot'), 'untrusted-kind@calling.invalid'), publisher(51, metadata('User'), 'open-claudia:other-bot'),
|
|
542
|
+
publisher(52, undefined, 'older-client@calling.invalid'),
|
|
543
|
+
] } } });
|
|
544
|
+
assert.deepStrictEqual([...legacy.subscribers.keys()], [43, 50, 52], 'legacy live publishers keep display-prefix behavior regardless of spoofed or absent metadata');
|
|
545
|
+
} finally { await legacy.close(); }
|
|
546
|
+
}
|
|
547
|
+
|
|
487
548
|
async function testAssignedRelayTransportLifetime() {
|
|
488
549
|
const { RTCPeerConnection } = require('werift');
|
|
489
550
|
const originalExpiry = Date.now() + 3600000;
|
|
@@ -538,6 +599,7 @@ async function testAssignedRelayTransportLifetime() {
|
|
|
538
599
|
}
|
|
539
600
|
|
|
540
601
|
(async () => {
|
|
602
|
+
await testTrustedPublisherMetadata();
|
|
541
603
|
await testAssignedRelayTransportLifetime();
|
|
542
604
|
await testManagedRoomCredentials();
|
|
543
605
|
await testSpeakSerialization();
|
|
@@ -464,9 +464,10 @@ assert.match(pkg.description, /provider-agnostic coding-agent harness/i);
|
|
|
464
464
|
// tool_name "Bash" and the deny gate caught the probe, so the gate no longer
|
|
465
465
|
// requires unified_exec off. Push approved by Sumeet before release.
|
|
466
466
|
// 3.4.12: Sumeet approved the full calling rollout on 2026-09-05; preserve assigned media configuration across canary changes.
|
|
467
|
+
// 3.4.14: bot managed-call consumer (subscribe only to gateway-authenticated User publishers) — part of the Janus calling plan Sumeet approved on 2026-09-05.
|
|
467
468
|
// 3.4.13: Codex usage accounting fix — Sumeet approved the three-bug fix on 2026-09-05 ("Yes");
|
|
468
469
|
// prepared 2026-09-06 for his release go. Rollout-based Codex context, per-turn ledger, sub-agent + quota accounting.
|
|
469
|
-
assert.strictEqual(pkg.version, "3.4.
|
|
470
|
+
assert.strictEqual(pkg.version, "3.4.14", "release version must remain unchanged without explicit approval");
|
|
470
471
|
for (const keyword of ["claude", "codex", "coding-agent", "provider-agnostic"]) {
|
|
471
472
|
assert.ok(pkg.keywords.includes(keyword), `package keyword missing: ${keyword}`);
|
|
472
473
|
}
|