instar 1.3.754 → 1.3.756
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +122 -3
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +20 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/ProfileIntentClassifier.d.ts +167 -0
- package/dist/core/ProfileIntentClassifier.d.ts.map +1 -0
- package/dist/core/ProfileIntentClassifier.js +421 -0
- package/dist/core/ProfileIntentClassifier.js.map +1 -0
- package/dist/core/componentCategories.d.ts.map +1 -1
- package/dist/core/componentCategories.js +5 -0
- package/dist/core/componentCategories.js.map +1 -1
- package/dist/core/devGatedFeatures.d.ts.map +1 -1
- package/dist/core/devGatedFeatures.js +6 -0
- package/dist/core/devGatedFeatures.js.map +1 -1
- package/dist/core/topicProfileIngress.d.ts +14 -2
- package/dist/core/topicProfileIngress.d.ts.map +1 -1
- package/dist/core/topicProfileIngress.js +15 -44
- package/dist/core/topicProfileIngress.js.map +1 -1
- package/dist/data/llmBenchCoverage.d.ts.map +1 -1
- package/dist/data/llmBenchCoverage.js +9 -0
- package/dist/data/llmBenchCoverage.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lint-model-registry-freshness.mjs +77 -11
- package/scripts/model-registry-freshness.manifest.json +34 -28
- package/src/data/builtin-manifest.json +2 -2
- package/src/data/llmBenchCoverage.ts +9 -0
- package/upgrades/1.3.755.md +75 -0
- package/upgrades/1.3.756.md +27 -0
- package/upgrades/side-effects/doorway-model-registry-inc1.md +89 -0
- package/upgrades/side-effects/topicprofile-intent-llm-rebuild.md +87 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/commands/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAuDH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAU3D,OAAO,EAAE,eAAe,EAAiC,MAAM,iCAAiC,CAAC;AAyBjG,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AA6H7D,OAAO,KAAK,EAAW,oBAAoB,EAAe,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAgFtD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,gBAAgB,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC1C,OAAO,CAUT;AAyID,UAAU,YAAY;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;2DACuD;IACvD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAgmDD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,YAAY,EACpB,YAAY,EAAE,oBAAoB,GAAG,IAAI,GACxC;IACD,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,CAqBA;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,cAAc,EAAE,cAAc,EAC9B,YAAY,CAAC,EAAE,YAAY,EAC3B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,EACzB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,EAGvE,UAAU,CAAC,EAAE,MAAM,OAAO,8BAA8B,EAAE,WAAW,GAAG,IAAI,EAK5E,qBAAqB,CAAC,EAAE,MAAM,OAAO,gCAAgC,EAAE,kBAAkB,GAAG,IAAI,EAKhG,mBAAmB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,EAQrD,oBAAoB,CAAC,EAAE,MAAM;IAC3B,YAAY,EAAE,OAAO,kBAAkB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IACrE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAAC;IAC3C,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,IAAI,GACP,IAAI,CAonBN;AA2lBD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAs0lBtE;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsDzE;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuD5E"}
|
package/dist/commands/server.js
CHANGED
|
@@ -32,6 +32,7 @@ import { PrHandLease } from '../core/PrHandLease.js';
|
|
|
32
32
|
import { ConversationRegistry } from '../core/ConversationRegistry.js';
|
|
33
33
|
import { claimSuspensionExcludesPin } from '../core/TopicClaimAnnotationStore.js';
|
|
34
34
|
import { parseProfileTrigger, platformMessageIdFrom } from '../core/topicProfileIngress.js';
|
|
35
|
+
import { classifyProfileIntent, toProfilePatch, } from '../core/ProfileIntentClassifier.js';
|
|
35
36
|
import { slugifyChannelName } from '../messaging/slack/sanitize.js';
|
|
36
37
|
import { TopicProfileOrchestrator, resolvedToApplied, } from '../core/TopicProfileOrchestrator.js';
|
|
37
38
|
import { CodexResumeMap } from '../core/CodexResumeMap.js';
|
|
@@ -704,6 +705,20 @@ function appendTopicProfileAudit(stateDir, event) {
|
|
|
704
705
|
}
|
|
705
706
|
let _projectDir = process.cwd();
|
|
706
707
|
let _sharedIntelligence = null;
|
|
708
|
+
// Offender #1 conversion (docs/specs/keyword-intent-conversions-1-and-3.md): the
|
|
709
|
+
// framework/model/thinking WRITE decision is inferred by the ProfileIntentClassifier
|
|
710
|
+
// (LLM + recent conversation), replacing the removed keyword regexes in
|
|
711
|
+
// parseProfileTrigger. Dev-gated dark (resolveDevAgentGate) + dry-run FIRST: while
|
|
712
|
+
// dark or dry-run the message ALWAYS passes through (never actuated); the classifier
|
|
713
|
+
// still runs on a dev agent and LOGS would-actuate vs would-pass to
|
|
714
|
+
// logs/profile-intent.jsonl for the soak. Resolved once in startServer.
|
|
715
|
+
let _profileIntentEnabled = false;
|
|
716
|
+
let _profileIntentDryRun = true;
|
|
717
|
+
let _profileIntentMinConfidence = 0.85;
|
|
718
|
+
let _profileIntentTimeoutMs = 4000;
|
|
719
|
+
let _profileIntentContextTurns = 6;
|
|
720
|
+
let _profileIntentModelTier = 'fast';
|
|
721
|
+
let _profileIntentStateDir = '';
|
|
707
722
|
let _selfKnowledgeTree = null;
|
|
708
723
|
let _slackAdapter = null;
|
|
709
724
|
// WS1.1 dispatch-to-owner (Slack arm): the owner-side bridge reconstructs a Slack
|
|
@@ -1669,6 +1684,42 @@ function messageToPipeline(msg, topicName) {
|
|
|
1669
1684
|
* a message carrying platform forward metadata falls through as normal
|
|
1670
1685
|
* conversation regardless of sender.
|
|
1671
1686
|
*/
|
|
1687
|
+
/**
|
|
1688
|
+
* Offender #1 conversion soak log: one JSONL line per LLM-engaged
|
|
1689
|
+
* ProfileIntentClassifier decision (docs/specs/keyword-intent-conversions-1-and-3.md).
|
|
1690
|
+
* A prefilter-skip is always a would-pass and the bulk of traffic — skipping it
|
|
1691
|
+
* cuts volume AND the privacy surface to messages that named a profile signal and
|
|
1692
|
+
* actually reached the classifier. Observability only — never gates the message.
|
|
1693
|
+
*/
|
|
1694
|
+
function logProfileIntent(topicId, text, result, acted) {
|
|
1695
|
+
try {
|
|
1696
|
+
if (result.source === 'prefilter-skip')
|
|
1697
|
+
return;
|
|
1698
|
+
if (!_profileIntentStateDir)
|
|
1699
|
+
return;
|
|
1700
|
+
const logDir = path.join(_profileIntentStateDir, 'logs');
|
|
1701
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
1702
|
+
const decision = result.isChange ? (acted ? 'actuate' : 'would-actuate') : 'pass';
|
|
1703
|
+
const line = JSON.stringify({
|
|
1704
|
+
ts: new Date().toISOString(),
|
|
1705
|
+
topicId,
|
|
1706
|
+
decision,
|
|
1707
|
+
dryRun: _profileIntentDryRun,
|
|
1708
|
+
source: result.source,
|
|
1709
|
+
intent: result.intent,
|
|
1710
|
+
value: result.value,
|
|
1711
|
+
confidence: result.confidence,
|
|
1712
|
+
reason: result.reason,
|
|
1713
|
+
// NO raw message content: the enum-bounded fields above are what the FP-rate
|
|
1714
|
+
// soak needs, and the resolved `value` is already a closed-enum member. We
|
|
1715
|
+
// record only the message LENGTH (non-content) — mirroring the codebase's
|
|
1716
|
+
// dev-soak convention of never persisting a raw operator quote.
|
|
1717
|
+
textLen: typeof text === 'string' ? text.length : 0,
|
|
1718
|
+
});
|
|
1719
|
+
fs.appendFileSync(path.join(logDir, 'profile-intent.jsonl'), line + '\n');
|
|
1720
|
+
}
|
|
1721
|
+
catch { /* @silent-fallback-ok: the soak audit is observability-only — a log write fault must never gate or throw out of the message path (the classifier decision already stands) */ }
|
|
1722
|
+
}
|
|
1672
1723
|
async function handleTopicProfileIngress(telegram, topicId, text, telegramUserId, msg) {
|
|
1673
1724
|
const surface = _topicProfileWriteSurface;
|
|
1674
1725
|
const slots = _topicProfileConfirmSlots;
|
|
@@ -1683,10 +1734,65 @@ async function handleTopicProfileIngress(telegram, topicId, text, telegramUserId
|
|
|
1683
1734
|
catch { /* @silent-fallback-ok: a trust-floor read fault fails toward NOT-a-trigger (deny-by-default) — the conversational profile parse never runs for an unauthorized turn (TOPIC-PROFILE-SPEC §10.1) */ }
|
|
1684
1735
|
if (!authorized)
|
|
1685
1736
|
return false;
|
|
1686
|
-
const trigger = parseProfileTrigger(text);
|
|
1687
|
-
if (!trigger)
|
|
1688
|
-
return false;
|
|
1689
1737
|
const forwarded = msg.metadata?.forwarded === true;
|
|
1738
|
+
const trigger = parseProfileTrigger(text);
|
|
1739
|
+
if (!trigger) {
|
|
1740
|
+
// Offender #1 conversion (docs/specs/keyword-intent-conversions-1-and-3.md):
|
|
1741
|
+
// the framework/model/thinking WRITE decision moved OUT of parseProfileTrigger
|
|
1742
|
+
// (keyword regexes) into the ProfileIntentClassifier — an LLM reasoning over
|
|
1743
|
+
// the message + recent conversation with structured-enum output, per the
|
|
1744
|
+
// constitutional standard "Intelligence Infers, Keywords Only Guard".
|
|
1745
|
+
// Dev-gated dark + dry-run FIRST; fail-OPEN on every uncertainty.
|
|
1746
|
+
if (forwarded)
|
|
1747
|
+
return false; // forwarded content is never a command
|
|
1748
|
+
if (!_profileIntentEnabled)
|
|
1749
|
+
return false; // fleet-dark → pass to the agent
|
|
1750
|
+
let conversationContext = [];
|
|
1751
|
+
try {
|
|
1752
|
+
// Fetch one extra turn, then drop a trailing turn equal to THIS message —
|
|
1753
|
+
// getTopicHistory (oldest→newest) usually already contains the just-logged
|
|
1754
|
+
// inbound row, so without this the model would see the message twice (once
|
|
1755
|
+
// as MESSAGE, once as the newest CONTEXT turn).
|
|
1756
|
+
const hist = telegram.getTopicHistory?.(topicId, _profileIntentContextTurns + 1) ?? [];
|
|
1757
|
+
conversationContext = hist.map((h) => ({ fromUser: !!h.fromUser, text: String(h.text ?? '') }));
|
|
1758
|
+
const trimmed = text.trim();
|
|
1759
|
+
while (conversationContext.length > 0
|
|
1760
|
+
&& conversationContext[conversationContext.length - 1].fromUser
|
|
1761
|
+
&& conversationContext[conversationContext.length - 1].text.trim() === trimmed) {
|
|
1762
|
+
conversationContext.pop();
|
|
1763
|
+
}
|
|
1764
|
+
conversationContext = conversationContext.slice(-_profileIntentContextTurns);
|
|
1765
|
+
}
|
|
1766
|
+
catch { /* @silent-fallback-ok — context is best-effort; classify on the message alone */ }
|
|
1767
|
+
const result = await classifyProfileIntent({
|
|
1768
|
+
text,
|
|
1769
|
+
conversationContext,
|
|
1770
|
+
intelligence: _sharedIntelligence,
|
|
1771
|
+
minConfidence: _profileIntentMinConfidence,
|
|
1772
|
+
timeoutMs: _profileIntentTimeoutMs,
|
|
1773
|
+
maxContextTurns: _profileIntentContextTurns,
|
|
1774
|
+
modelTier: _profileIntentModelTier,
|
|
1775
|
+
});
|
|
1776
|
+
const willAct = result.isChange && !_profileIntentDryRun;
|
|
1777
|
+
logProfileIntent(topicId, text, result, willAct);
|
|
1778
|
+
// Dry-run (the soak) / fail-open / pass-through: log would-actuate vs
|
|
1779
|
+
// would-pass, but pass the message through untouched. Real actuation needs a
|
|
1780
|
+
// deliberate dryRun:false, AND fail-open means uncertainty never actuates.
|
|
1781
|
+
if (!willAct)
|
|
1782
|
+
return false;
|
|
1783
|
+
const patch = toProfilePatch(result);
|
|
1784
|
+
if (!patch)
|
|
1785
|
+
return false;
|
|
1786
|
+
const applyPrincipal = { kind: 'operator', platform: 'telegram', uid: String(telegramUserId) };
|
|
1787
|
+
const applyResult = await surface.applyWrite({
|
|
1788
|
+
topicKey: String(topicId), patch, principal: applyPrincipal, origin: 'conversational', discloseInReply: true,
|
|
1789
|
+
});
|
|
1790
|
+
try {
|
|
1791
|
+
await telegram.sendToTopic(topicId, applyResult.reply);
|
|
1792
|
+
}
|
|
1793
|
+
catch { /* @silent-fallback-ok: best-effort disclosure send (TOPIC-PROFILE-SPEC §10.1) */ }
|
|
1794
|
+
return true;
|
|
1795
|
+
}
|
|
1690
1796
|
if (forwarded)
|
|
1691
1797
|
return false;
|
|
1692
1798
|
const topicKey = String(topicId);
|
|
@@ -5329,6 +5435,19 @@ export async function startServer(options) {
|
|
|
5329
5435
|
const { TopicProfileResolver } = await import('../core/TopicProfileResolver.js');
|
|
5330
5436
|
const { normalizeTierEscalationConfig } = await import('../core/ModelTierEscalation.js');
|
|
5331
5437
|
const topicProfilesCfg = config.topicProfiles;
|
|
5438
|
+
// Offender #1 conversion: resolve the ProfileIntentClassifier settings ONCE
|
|
5439
|
+
// (the module-level ingress handler has no config in scope). `enabled` rides
|
|
5440
|
+
// resolveDevAgentGate (dark on the fleet, live on a dev agent — registered in
|
|
5441
|
+
// DEV_GATED_FEATURES, configPath topicProfiles.intentClassifier.enabled);
|
|
5442
|
+
// dryRun ships true (the dry-run canary — actuates only on a deliberate flip).
|
|
5443
|
+
const _intentCfg = topicProfilesCfg?.intentClassifier;
|
|
5444
|
+
_profileIntentEnabled = resolveDevAgentGate(_intentCfg?.enabled, config);
|
|
5445
|
+
_profileIntentDryRun = _intentCfg?.dryRun ?? true;
|
|
5446
|
+
_profileIntentMinConfidence = _intentCfg?.minConfidence ?? 0.85;
|
|
5447
|
+
_profileIntentTimeoutMs = _intentCfg?.timeoutMs ?? 4000;
|
|
5448
|
+
_profileIntentContextTurns = _intentCfg?.contextWindowTurns ?? 6;
|
|
5449
|
+
_profileIntentModelTier = _intentCfg?.modelTier ?? 'fast';
|
|
5450
|
+
_profileIntentStateDir = config.stateDir;
|
|
5332
5451
|
_topicProfileStore = new TopicProfileStore({
|
|
5333
5452
|
stateFilePath: path.join(config.stateDir, 'state', 'topic-profiles.json'),
|
|
5334
5453
|
legacyFrameworksPath: path.join(config.stateDir, 'state', 'topic-frameworks.json'),
|