@yeaft/webchat-agent 1.0.430 → 1.0.431
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"1.0.
|
|
1
|
+
{"version":"1.0.431"}
|
package/package.json
CHANGED
|
@@ -7,6 +7,28 @@ function policyError(message) {
|
|
|
7
7
|
return error;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
function diagnosticValue(value) {
|
|
11
|
+
return String(value ?? '')
|
|
12
|
+
.replace(/[^a-zA-Z0-9._:-]+/g, '-')
|
|
13
|
+
.replace(/^-+|-+$/g, '')
|
|
14
|
+
.slice(0, 128) || 'none';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function assignmentError(message, {
|
|
18
|
+
policy, stageType, candidates = [], excluded = [], fallback = 'not-attempted',
|
|
19
|
+
}) {
|
|
20
|
+
const context = [
|
|
21
|
+
`mode=${diagnosticValue(policy.mode)}`,
|
|
22
|
+
`capability=${diagnosticValue(policy.capability || stageType)}`,
|
|
23
|
+
`fallback=${diagnosticValue(fallback)}`,
|
|
24
|
+
`candidates=${candidates.length
|
|
25
|
+
? candidates.map(vp => diagnosticValue(vp?.id || vp)).sort().join(',')
|
|
26
|
+
: 'none'}`,
|
|
27
|
+
`excluded=${excluded.size ? [...excluded].map(diagnosticValue).sort().join(',') : 'none'}`,
|
|
28
|
+
].join('; ');
|
|
29
|
+
return policyError(`${message} (${context})`);
|
|
30
|
+
}
|
|
31
|
+
|
|
10
32
|
const CAPABILITY_TERMS = Object.freeze({
|
|
11
33
|
triage: ['triage', 'requirement', 'flow', 'product', 'strategy', 'cross-domain', 'analysis'],
|
|
12
34
|
implement: ['implement', 'engineer', 'developer', 'engineering', 'systems', 'code', 'execution'],
|
|
@@ -60,23 +82,46 @@ function priorVpIdsForSeparation(policy, priorRuns) {
|
|
|
60
82
|
export function selectWorkItemVp({ policy: rawPolicy, stageType, vps, priorRuns = [] }) {
|
|
61
83
|
const policy = normalizeAssignmentPolicy(rawPolicy, stageType);
|
|
62
84
|
const all = Array.isArray(vps) ? vps.filter(vp => vp?.id) : [];
|
|
63
|
-
if (all.length === 0) throw policyError('Work Center has no available VPs');
|
|
64
|
-
const byId = new Map(all.map(vp => [vp.id, vp]));
|
|
65
85
|
const excluded = priorVpIdsForSeparation(policy, priorRuns);
|
|
86
|
+
if (all.length === 0) {
|
|
87
|
+
throw assignmentError('Work Center has no available VPs', {
|
|
88
|
+
policy, stageType, candidates: [], excluded,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const byId = new Map(all.map(vp => [vp.id, vp]));
|
|
66
92
|
|
|
67
93
|
if (policy.mode === 'fixed') {
|
|
68
94
|
const fixed = byId.get(policy.fixedVpId);
|
|
69
|
-
if (!fixed)
|
|
70
|
-
|
|
95
|
+
if (!fixed) {
|
|
96
|
+
throw assignmentError(`Fixed Work Center VP is unavailable: ${diagnosticValue(policy.fixedVpId)}`, {
|
|
97
|
+
policy, stageType, candidates: [policy.fixedVpId], excluded,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (excluded.has(fixed.id)) {
|
|
101
|
+
throw assignmentError(`Work Center separation policy excludes VP: ${diagnosticValue(fixed.id)}`, {
|
|
102
|
+
policy, stageType, candidates: [fixed], excluded,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
71
105
|
return { vp: fixed, reason: `fixed:${fixed.id}`, policy };
|
|
72
106
|
}
|
|
73
107
|
|
|
108
|
+
const configuredCandidates = ['pool', 'planned'].includes(policy.mode)
|
|
109
|
+
? policy.candidateVpIds
|
|
110
|
+
: all;
|
|
74
111
|
const pool = ['pool', 'planned'].includes(policy.mode)
|
|
75
112
|
? policy.candidateVpIds.map(id => byId.get(id)).filter(Boolean)
|
|
76
113
|
: all;
|
|
77
|
-
if (pool.length === 0)
|
|
114
|
+
if (pool.length === 0) {
|
|
115
|
+
throw assignmentError('No configured Work Center VP candidates are available', {
|
|
116
|
+
policy, stageType, candidates: configuredCandidates, excluded,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
78
119
|
const eligible = pool.filter(vp => !excluded.has(vp.id));
|
|
79
|
-
if (eligible.length === 0)
|
|
120
|
+
if (eligible.length === 0) {
|
|
121
|
+
throw assignmentError('No Work Center VP satisfies the stage separation policy', {
|
|
122
|
+
policy, stageType, candidates: pool, excluded,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
80
125
|
if (policy.mode === 'planned') {
|
|
81
126
|
return {
|
|
82
127
|
vp: eligible[0],
|
|
@@ -99,7 +144,11 @@ export function selectWorkItemVp({ policy: rawPolicy, stageType, vps, priorRuns
|
|
|
99
144
|
policy,
|
|
100
145
|
};
|
|
101
146
|
}
|
|
102
|
-
|
|
147
|
+
return {
|
|
148
|
+
vp: fallback[0].vp,
|
|
149
|
+
reason: `${policy.mode}:${policy.capability || stageType}:fallback=${stageType}:eligible-id:score=0`,
|
|
150
|
+
policy,
|
|
151
|
+
};
|
|
103
152
|
}
|
|
104
153
|
return {
|
|
105
154
|
vp: ranked[0].vp,
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { sanitizeDiagnosticText } from './debug-projection.js';
|
|
2
|
+
|
|
3
|
+
const MAX_FAILURE_INSPECTION_LENGTH = 16_000;
|
|
4
|
+
const MAX_MODEL_FAILURE_DIAGNOSTIC_BYTES = 2_000;
|
|
5
|
+
const SAFE_FAILURE_FALLBACK = 'The Action failed. Sensitive details were omitted.';
|
|
6
|
+
const PROVIDER_TOKEN_PATTERN = /\b(?:sk-(?:proj-)?[A-Za-z0-9_-]{12,}|github_pat_[A-Za-z0-9_]{12,}|gh[pousr]_[A-Za-z0-9_]{12,}|xox[baprs]-[A-Za-z0-9-]{12,}|AKIA[A-Z0-9]{12,})\b/i;
|
|
7
|
+
const HIGH_ENTROPY_SECRET_PATTERN = /\b(?=[A-Za-z0-9_./+=-]{32,}\b)(?=[A-Za-z0-9_./+=-]*[A-Za-z])(?=[A-Za-z0-9_./+=-]*\d)[A-Za-z0-9_./+=-]+\b/;
|
|
8
|
+
const LOCAL_PATH_ASSIGNMENT_PATTERN = /\b(?:path|cwd|file|filename|directory)\s*[:=]\s*(?:\/(?!\/)|[A-Za-z]:\\|\\\\)/i;
|
|
9
|
+
const POSIX_ABSOLUTE_PATH_PATTERN = /(?:^|[\s("'`])\/(?!\/)[^\r\n]*/m;
|
|
10
|
+
const WINDOWS_ABSOLUTE_PATH_PATTERN = /(?:^|[\s("'`])(?:[A-Za-z]:\\|\\\\)[^\r\n]*/m;
|
|
11
|
+
|
|
12
|
+
function containsUnsafeFailureText(value) {
|
|
13
|
+
return PROVIDER_TOKEN_PATTERN.test(value)
|
|
14
|
+
|| HIGH_ENTROPY_SECRET_PATTERN.test(value)
|
|
15
|
+
|| LOCAL_PATH_ASSIGNMENT_PATTERN.test(value)
|
|
16
|
+
|| POSIX_ABSOLUTE_PATH_PATTERN.test(value)
|
|
17
|
+
|| WINDOWS_ABSOLUTE_PATH_PATTERN.test(value);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Project a persisted Run error into bounded, model-safe Action context. */
|
|
21
|
+
export function sanitizeModelFailureDiagnostic(value) {
|
|
22
|
+
const raw = typeof value === 'string'
|
|
23
|
+
? value.trim().slice(0, MAX_FAILURE_INSPECTION_LENGTH)
|
|
24
|
+
: '';
|
|
25
|
+
if (!raw) return null;
|
|
26
|
+
if (containsUnsafeFailureText(raw)) return SAFE_FAILURE_FALLBACK;
|
|
27
|
+
return sanitizeDiagnosticText(raw, MAX_MODEL_FAILURE_DIAGNOSTIC_BYTES) || null;
|
|
28
|
+
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from './action-identity.js';
|
|
9
9
|
import { sessionMessageQuotePrompt } from '../session-message-quote.js';
|
|
10
10
|
import { normalizeSessionContextSnapshot } from './session-context.js';
|
|
11
|
+
import { sanitizeModelFailureDiagnostic } from './failure-diagnostic.js';
|
|
11
12
|
|
|
12
13
|
export const MAINLINE_CONTEXT_HARD_LIMIT_BYTES = 64 * 1024;
|
|
13
14
|
export const MAINLINE_CONTEXT_TARGET_MIN_BYTES = 16 * 1024;
|
|
@@ -314,6 +315,7 @@ export function buildMainlineProjection(detail) {
|
|
|
314
315
|
outputs: normalizeOutputs(run.outputs),
|
|
315
316
|
reviewDecision: run.reviewDecision || null,
|
|
316
317
|
waitingReason: run.waitingReason || null,
|
|
318
|
+
error: sanitizeModelFailureDiagnostic(run.error),
|
|
317
319
|
endedAt: run.endedAt || null,
|
|
318
320
|
};
|
|
319
321
|
}
|